Arrayfun with a function that takes multiple inputs

152 visualizaciones (últimos 30 días)
Noah Chrein
Noah Chrein el 1 de Jul. de 2015
Respondida: saadani seifeddine el 13 de Mzo. de 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.

Respuesta aceptada

Steven Lord
Steven Lord el 1 de Jul. de 2015
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 comentarios
John D'Errico
John D'Errico el 1 de Jul. de 2015
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.
Steven Lord
Steven Lord el 1 de Jul. de 2015
@(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 :)

Iniciar sesión para comentar.

Más respuestas (3)

Céldor
Céldor el 15 de Sept. de 2016
Editada: Céldor el 16 de Sept. de 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 :)

Adam
Adam el 1 de Jul. de 2015
Editada: Adam el 1 de Jul. de 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 comentarios
Steven Lord
Steven Lord el 1 de Jul. de 2015
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.
Adam
Adam el 1 de Jul. de 2015
Editada: Adam el 1 de Jul. de 2015
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.

Iniciar sesión para comentar.


saadani seifeddine
saadani seifeddine el 13 de Mzo. de 2017
[B1,...,Bm] = arrayfun(@(x) func(x,var1,...,vark),A1,...,An)
...
function[Y]=func(X,Var1,...,Vark)
...

Categorías

Más información sobre Loops and Conditional Statements en Help Center y File Exchange.

Productos

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by