Using arrayfun to apply two function arguments in each combination

Let i = [1 2]

and j = [3 5]

. Now in the octave:

arrayfun(@(x,y) x+y,i,j)

      

we get [4 7]

. But I want to apply the function to combinations of i

vs. j

to receive [i(1)+j(1) i(1)+j(2) i(2)+j(1) i(2)+j(2)]=[4 6 5 7]

.

How to do it? I know I can use for-loopsl, but I need vector code because it's faster.

+3


source to share


2 answers


In Octave, to find the sum between two vectors, you can use a truly vectorial approach with broadcasting

like this -

out = reshape(ii(:).' + jj(:),[],1)

      

Here's a runtime test ideone

for input size vectors 1 x 100

each -

-------------------- With FOR-LOOP
Elapsed time is 0.148444 seconds.
-------------------- With BROADCASTING
Elapsed time is 0.00038299 seconds.

      

If you want to keep it general to accommodate operations other than just summing, you can use anonymous functions, like:

func1 = @(I,J) I+J;
out = reshape(func1(ii,jj.'),1,[])

      




In MATLAB, you can do the same with two alternatives bsxfun

as shown below.

I am. bsxfun

with anonymous function -

func1 = @(I,J) I+J;
out = reshape(bsxfun(func1,ii(:).',jj(:)),1,[]);

      

II. bsxfun

with @plus inline -

out = reshape(bsxfun(@plus,ii(:).',jj(:)),1,[]);

      

With input vectors of size 1 x 10000

each, the runtime at my end was -

-------------------- With FOR-LOOP
Elapsed time is 1.193941 seconds.
-------------------- With BSXFUN ANONYMOUS
Elapsed time is 0.252825 seconds.
-------------------- With BSXFUN BUILTIN
Elapsed time is 0.215066 seconds.

      

+1


source


Firstly, your first example is not the best, because the most efficient way to accomplish what you are doing with arrayfun

would be vectorizing:

a = [1 2];
b = [3 5];
out = a+b

      

Second, in Matlab at least arrayfun

not necessarily faster than a simple loop for

. arrayfun

is mostly convenience (especially for more advanced options). Try this simple sync example:

a = 1:1e5;
b = a+1;

y = arrayfun(@(x,y)x+y,a,b); % Warm up
tic
y = arrayfun(@(x,y)x+y,a,b);
toc

y = zeros(1,numel(a));
for k = 1:numel(a)
    y(k) = a(k)+b(k); % Warm up
end
tic
y = zeros(1,numel(a));
for k = 1:numel(a)
    y(k) = a(k)+b(k);
end
toc

      



In Matlab R2015a, the loop method is for

more than 70 times faster to run from the Command window and 260 times faster when run from the M file function. The octave may be different, but you should experiment.

Finally, you can accomplish what you want with meshgrid

:

a = [1 2];
b = [3 5];
[x,y] = meshgrid(a,b);
out = x(:).'+y(:).'

      

which returns [4 6 5 7]

as in your question. You can also use ndgrid

to get the result in a different order.

+1


source







All Articles