How to implement a function similar to cellfun? - matlab

My problem is about passing parameters to the other function; I don't know how to divide varargin and pass values as parameters.
function A = mycellfun(func, varargin)
A = cell(size(varargin{1}));
for ii = 1:numel(A)
A{i} = func(varargin{ ??? })
end
end
...
S = mycellfun(#plus, {1 [2 3]}, {4 [5 6]})

You need to use cellfun to group corresponding entries in each of the elements in varargin
inputs = cellfun(#(varargin)varargin, varargin{:}, 'UniformOutput', false);
The anonymous function #(varargin)varargin accepts a variable number of inputs (varargin) as a cell array and then simply returns this cell array. It's actually no different than the function:
function v = func(varargin)
v = varargin;
end
So for example:
varargin = {{1, 2, 3}, {4, 5, 6}};
inputs = cellfun(#(varargin)varargin, varargin{:}, 'UniformOutput', false);
% {{1, 4}, {2, 5}, {3, 6}}
And then you can loop through inputs and each cell element will contain all inputs for a given iteration. You can then use {:} indexing to create a comma separated list and pass this as inputs to func.
A = cell(size(inputs));
for k = 1:numel(inputs)
A{k} = func(inputs{k}{:});
end

Related

Syntax for evaluating multiple variables for function

I'm trying to do something like
f = [x+1 y+2]
values = [1 2]
f(values) = [2 4]
(not proper syntax)
f(values) only works for taking one variable?
Try this:
f = {#(x) (x+1); #(y) (y+2)}; %//create a cell array of your function handlers
values = [1 2];
%//convert your input values to a cell array
length = numel(values);
v = mat2cell( values, 1, ones(length,1) ).' ;
%// f(v)
results = cellfun(#(x,y) x(y), f, v);

Apply a cell array of functions to a value

I define a cell array that contains values and functions:
>> A = {1, 2, 3; #(x) x+5, #(x) x+10, 5}
A =
[ 1] [ 2] [3]
#(x)x+5 #(x)x+10 [5]
Does anyone know how to apply this cell array to a value? For instance, when x = 2, the application returns another cell array:
[ 1] [ 2] [3]
[ 7] [ 12] [5]
Define your constants as functions:
A = {#(x)1, #(x)2, #(x)3; #(x) x+5, #(x) x+10, #(x)5}
now use cellfun:
k = 2;
cellfun(#(x)x(k),A)
Also note that if you want to apply multiple k values at once (e.g. k = 1:5) you will need to edit your constant functions in A from this form #(x) n to something like #(x) n*ones(size(x)) and then change the cellfun call to:
cellfun(#(x)x(k),A, 'uni',0)
To answer the question from your comments:
is it possible to refer to other cells in a function in a cell array?
For instance, can we define something like A = {#(x)1, #(x)2, the 1st cell + the 2nd cell, #(x)4}?
You define A as follows:
A = {#(x)1, #(x)2, #(x)(A{1}(x)+A{2}(x)), #(x)4}
Wouldn't it be better to define the cell-array/function thingie like this:
A = #(x) {1, 2, 3; x+5, x+10, 5};
Then you can apply it by simpliy doing
A(2)
Maybe you can even use normal matrices instead of cell array here:
A = #(x) [1, 2, 3; x+5, x+10, 5];

Append values to several cells in cell array

Imagine I have a cell array
A = {0, 1 ,2, 3, ...}
and indice vector
I = [0, 1, 0, 1, 0, ...]
and values
V = [2, 3]
and I want something like
A{I} = [A{I}; V]' = {0, [1 2], 2, [3 3], ....};
That is, I want to append several values to some cells of a cell array at once. How would I do that most elegantly/efficiently? :)
You can use cellfun
A(I==1) = cellfun( #(x,y) [x y], A(I==1), num2cell(V), 'UniformOutput', 0 );
Note the usage of regular subscripting (using (), rather than {}) to index the chosen cell elements using I==1. Also note that V is passed as a cell array (using num2cell) and not as a regular array.

Sort 2d matrix in Matlab

I have a 2d matrix, the first column is numeric, second is string and third is string, I want to sort by the first column. Here is my code used to create the loop.
Thanks
for i = 1:length(queries)
for j = 1:length(textures)
results{i * j, 1} = HI(queries{i, 2}, textures{j, 2});
results{i * j, 2} = textures{j, 3};
results{i * j, 3} = queries{i, 3};
end
results = sort(results, 1);
end
Use sortrows:
c = {0.608920898437500 'D1.gif' 'D106.gif'
0.803334960937500 'D1.gif' 'D109.gif'
0.831228027343750 'D1.gif' 'D26.gif'}; %// example data
cSorted = sortrows(c,1); %// sort rows according to first column
The result is
cSorted =
[0.6089] 'D1.gif' 'D106.gif'
[0.8033] 'D1.gif' 'D109.gif'
[0.8312] 'D1.gif' 'D26.gif'

Matlab Adjust in Vectorized Code

A few days ago I posted this question and got the following splendid solution:
fid = fopen('C:\Testes_veloc\test.txt', 'Wt');
fmt = sprintf('%s;%d;%%d;%d;%d;%%d;%%d;%%d;%%.4f \\n',str1,num1,0,2)
[a,b,c,d] = ndgrid(vect2,vect1,day,1:15);
out = sprintf(fmt, [d(:), c(:), b(:), a(:), reshape(permute(MD,[2,1,3,4]),[],1)]');
fprintf(fid, '%s', out);
The variables str1, num1, day, vect1, vect2 and MD are inputs of this function:
str1 is a string 1x1
num1 is an integer 1x1
day is a vector 10x1
vect1 is a vector 7x1
vect2 is a vector 180x1
MD is a 4D matrix (7x180x10x15)
The objective was to have a text file as follows:
result.txt:
RED;12;7;0;2;1;4;7;0.0140
RED;12;7;0;2;2;9;7;0.1484
RED;12;7;0;2;3;7;4;0.1787
RED;12;7;0;2;4;2;6;0.7891
RED;12;7;0;2;5;9;6;0.1160
RED;12;7;0;2;6;9;1;0.9893
However, str1 is not a 1x1 string; it's a vector of names (189000x1), that has the length of the text that I desire. In other words, instead of only 'RED', I have many different others strings. Is it possible to adjust this vectorized loop to this situation?
I tried this (add the str1(:) to the concatenation part), but unsuccessfully:
fmt = sprintf('%%s;%s;%d;%%d;%d;%d;%%d;%%d;%%d;%%.4f \\n',str1,num1,0,2)
out = sprintf(fmt, [str1 (:), d(:), c(:), b(:), a(:), reshape(permute(MD,[2,1,3,4]),[],1)]');
For example, str(1,:) = 'RED'; str(2,:) = 'FHAW'; str(3,:) = 'KI81'; a cell like this.
It fails to concatenate the string to the numbers. Does anyone have solution?
Thanks in advance.
sprintf (like fprintf) fills format fields using the arguments in the order they are provided. If you provide more arguments than the format calls for, these functions repeat the format with the additional functions:
sprintf('%s %i\n', 'a', 1, 'b', 2, 'c', 3)
% returns
ans =
a 1
b 2
c 3
Using Matlab's cell unravelling technique, you can prepare your arguments first, then pass them to the sprintf:
tmp = {'a', 1, 'b', 2, 'c', 3};
sprintf('%s %i\n', tmp{:})
You can get fancier by concatenating cell arrays:
tmp1 = {'a','b','c'};
tmp2 = [1 2 3];
tmp = [tmp1' num2cell(tmp2')]'
sprintf('%s %i\n', tmp{:})
% Returns
tmp =
'a' 'b' 'c'
[1] [2] [3]
ans =
a 1
b 2
c 3
Note that the layout of tmp is transposed of the layout in the format. This is because Matlab reads the data in row-major order, so it will march down rows, then columns, to get the arguments for sprintf.
So, in your scenario, you need to create a large cell array with your arguments, then pass that to sprintf.
fid = fopen('C:\Testes_veloc\test.txt', 'Wt');
fmt = sprintf('%%s;%d;%%d;%d;%d;%%d;%%d;%%d;%%.4f \\n',num1,0,2)
[a,b,c,d] = ndgrid(vect2,vect1,day,1:15);
tmp = [str(:) num2cell([d(:) c(:) b(:) a(:) reshape(permute(MD,[2,1,3,4]),[],1)]'])]';
fprintf(fid, fmt, tmp{:});
fclose(fid);