MATLAB Answers

0

Arrayfun with a function that takes multiple inputs

Asked by Noah Chrein on 1 Jul 2015
Latest activity Answered by saadani seifeddine on 13 Mar 2017
say I have an array that I want to run a function over each of its elements, I could easily do this with arrayfun(@f,v) where f is my function name and v is my vector.
But now say f is defined to take two input arguments, that is f(e,k) where e is an element of the same type as in the vector and k is something unrelated to the vector (for example an integer). how can I run arrayfun?
I would want to do this: arrayfun(@f,v,k), however, this runs arrayfun over two vectors v and k.
%%
Example:
Say mv = movingAvg(v,w) takes a vector v and does a moving average filter over it with width w, and returns the filtered vector to mv. Now say A = {v1,v2,...,vn} is an array of vectors. how could I use arrayfun to give me an array mA = {mv1,mv2,...,mvn} such that mvi = movingAvg(vi,10)?
I would assume that maybe mA = arrayfun(@movingAvg,A,10) or mA = arrayfun(@movingAvg,[A 10]) or something of that sort, but this is not true.

  0 Comments

Sign in to comment.

4 Answers

Answer by Steven Lord
on 1 Jul 2015
 Accepted Answer

This isn't the most efficient way to write "y = x+17" but it's good for demonstration.
k = 17;
x = 1:10;
y = arrayfun(@(z) plus(z, k), x)

  3 Comments

so what's happening in this code is that @(z) is telling array fun to run over z, then you specify the function plus to say "run plus over z", then x is plugged into z?
Is this how it should be interpreted? Thank you for the swift and simple answer,
Well, I'd argue not really. A simple interpretation is that
@(z) plus(z,k)
is an anonymous function, that is passed the argument k from your workspace, as a constant. This function is a function though of only ONE argument: z. Arrayfun thus sees a function of one argument only, so it is happy. That ancillary argument, k, is a constant as far as arrayfun is concerned. arrayfun does not care where a constant comes from, only that it is predefined.
@(z) plus(z, k) is a function [an anonymous function, if you want to be technical] that accepts one input, z, and calls the PLUS function with two inputs, z and k. Since k was defined when this anonymous function was created, and k does not appear in the list of input arguments, the anonymous function "remembers" the existing value.
ARRAYFUN requires the function you pass into it as the first input to accept one input per array over which it should iterate. I passed in one array, x, and so ARRAYFUN will call the function with one input. So the anonymous function satisfies ARRAYFUN's requirements. The PLUS function required you to specify two input arguments, and the anonymous function satisfied that requirement as well. So ARRAYFUN is happy, PLUS is happy, MATLAB is happy, and you're happy because your code runs :)

Sign in to comment.


Answer by Céldor
on 15 Sep 2016
Edited by Céldor
on 16 Sep 2016

I might be a little too late with an answer. However, I had recently a similar problem. I needed to test if vectors contain NaNs or zeros. I thought I would make an anonymous function with arrayfun and used an extra parameters as another function to apply, e.g. isnan(x) or my custom function iszero(x,tol) etc. The problem was a custom function because it needed tolerance to apply. I made something simple below:
iszero = @(x,tol) x < abs(tol) & x > -abs(tol);
I sorted it out everything using varargin:
TEST = @(sw, fun, varargin) arrayfun(@(x) fun(x,varargin{:}), sw, 'UniformOutput',true);
The great thing about varargin is that it is a cell. Even if it's used inside another function as a parameter, when it's empty MATLAB function simply ignores it. I can now use isnan(x) as well as iszero(x,tol) as follows:
a = [0.1 0.01 0.001 0.0001 0.000001];
TEST(a,@isnan)
ans =
0 0 0 0 0
TEST(a,iszero,0.1)
ans =
0 1 1 1 1
TEST(a,iszero,0.001)
ans =
0 0 0 1 1
Hope it helps :)

  0 Comments

Sign in to comment.


Answer by Adam
on 1 Jul 2015
Edited by Adam
on 1 Jul 2015

f = @(x,y) x.^2 + y.^2
g = @(x) f(x,3);
a = [1 2 3 4 5];
res = arrayfun( g, a );
is a general example that should give you the syntax you need. You bind a constant to your function handle rather than passing it as an argument to arrayfun so effectively your function, f, of 2 variables is replaced by a function, g, of one variable.
Edit: Note the @(x) part was missing from the definition of g when this was first posted.

  2 Comments

You missed a piece of the definition of g. As written, if x is defined before g is defined then g will no longer be an anonymous function handle by the time you get to the ARRAYFUN call and so ARRAYFUN will error. If x is not defined when you define g, you will receive an undefined function or variable error. The definition of g should be:
g = @(x) f(x, 3);
If you're more familiar with C++, think of this technique as similar in some ways to std::bind1st or std::bind2nd.
Ah yes, good point. I should have copy and pasted from my command window where I did get it right instead of typing it out from scratch! I will edit the original answer to include your correction.

Sign in to comment.


Answer by saadani seifeddine on 13 Mar 2017

[B1,...,Bm] = arrayfun(@(x) func(x,var1,...,vark),A1,...,An)
...
function[Y]=func(X,Var1,...,Vark)
...

  0 Comments

Sign in to comment.