Replacing arrayfun with for loop
Show older comments
Is there already a function that does what arrayfun does, but with a for loop?
In other words, is there a way to call a function on each element in an array using a for loop and output the values to a vector of cell arrays?
I am looking for something like:
outputvector = myforloopfunction(functionhandle(inputvector), 'UniformOutput', false)
I think this approach would be faster than use of the arrayfun, which is only faster than for loops on GPU, but not CPU.
Thank you.
3 Comments
Sven
on 2 Nov 2012
Please give an example - the functionhandle(inputvector) part above doesn't quite make sense. The first argument to your myforloopfunction above will not be a function handle, it will be the result of calling the function handle with an input vector.
If you want to just recreate arrayfun() but use loops instead of the internal MATLAB arrayfun, I highly doubt you will get much of a speed increase.
function out = testme(fcn, varargin)
out = cell(size(varargin{1}));
in = num2cell(cell2mat(cellfun(@(x)x(:), varargin, 'Un', 0)));
for i = 1:numel(out)
out{i} = fcn(in{i,:});
end
>> input = rand(400,1);
>> tic, for i = 1:1000, arrayfun(@plus, input, input*2,'Un',0); end, toc
Elapsed time is 3.988367 seconds.
>> tic, for i = 1:1000, testme(@plus, input, input*2); end, toc
Elapsed time is 13.339838 seconds.
@Justin: Sven is right: The line of code is not useful. I guess you mean:
output = myforloop(functionhandle, input1, input2)
@Sven: CELLFUN is really slow with anonymous functions. NUM2CELL and CELL2MAT are not really efficient also. Therefore I assume that the "in = ..." line is a hot spot of your implementation. Please run this (I cannot do it by myself, currently):
function out = testme(fcn, arg1, arg2)
out = cell(size(arg1));
for ii = 1:numel(out)
out{ii} = fcn(arg1(ii), arg2(ii));
end
Timings:
in1 = rand(400,1); % Do not shadow the builin "input"
in2 = in1 * 2; % Outside the tic-toc
tic, for k = 1:1000, arrayfun(@plus, in1, in2,'Un',0); end, toc
tic, for k = 1:1000, testme(@plus, in1, in2); end, toc
@Jan:
I agree completely about the slow bits - cellfun and wrapping/unwrapping arrays into cells will be a big overhead. Mine was a half-hearted attempt at making testme() take in an arbitrary number of parameters (like arrayfun does). That's why I asked Justin for an example - if we know exactly how many arguments we have, then like in your example (with 2 hard-coded arguments), we can index directly into those arrays. Here's how your code timed on my machine:
tic, for k = 1:1000, arrayfun(@plus, in1, in2,'Un',0); end, toc
tic, for k = 1:1000, testme(@plus, in1, in2); end, toc
Elapsed time is 0.902931 seconds.
Elapsed time is 1.570489 seconds.
Justin, this is closer to arrayfun() than my more generalised solution, but arrayfun still wins the race. I suggest you'll only get faster performance than arrayfun() in particular situations - ie, there won't be any general solution that you can code into a function that always gets faster performance than arrayfun.
Answers (0)
Categories
Find more on Loops and Conditional Statements in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!