I want to count all elements in a cell array, including those in "nested" cells.
For a cell array
>> C = {{{1,2},{3,4,5}},{{{6},{7},{8}},{9}},10}
C = {1x2 cell} {1x2 cell} [10]
The answer should be 10.
One way is to use [C{:}] repeatedly until there are no cells left and then use numel but there must be a better way?
Since you are only interested in the number of elements, here is a simplified version of flatten.m that #Ansari linked to:
function n = my_numel(A)
n = 0;
for i=1:numel(A)
if iscell(A{i})
n = n + my_numel(A{i});
else
n = n + numel(A{i});
end
end
end
The result:
>> C = {{{1,2},{3,4,5}},{{{6},{7},{8}},{9}},10};
>> my_numel(C)
ans =
10
EDIT:
If you are feeling lazy, we can let CELLPLOT do the counting:
hFig = figure('Visible','off');
num = numel( findobj(cellplot(C),'type','text') );
close(hFig)
Basically we create an invisible figure, plot the cell array, count how many "text" objects were created, then delete the invisible figure.
This is how the plot looks like underneath:
Put this in a function (say flatten.m) (code from MATLAB Central):
function C = flatten(A)
C = {};
for i=1:numel(A)
if(~iscell(A{i}))
C = [C,A{i}];
else
Ctemp = flatten(A{i});
C = [C,Ctemp{:}];
end
end
Then do numel(flatten(C)) to find the total number of elements.
If you don't like making a separate function, you can employ this clever (but nasty) piece of code for defining a flatten function using anonymous functions (code from here):
flatten = #(nested) feval(Y(#(flat) #(v) foldr(#(x, y) ifthenelse(iscell(x) | iscell(y), #() [flat(x), flat(y)], #() {x, y}), [], v)), nested);
Either way, you need to recurse to flatten the cell array then count.
Related
I have a cell with mathematical expressions that I would like to convert to a numeric array. It look as follows:
a = {};
a{1,1} = '0.55';
a{2,1} = '0.25 + 0.50';
Now I would like to receive the result (but preferably without a for loop):
b(1) = 0.55;
b(2) = 0.75;
How can I achieve this efficiently?
b = cellfun(#eval,a); will create an array b of the same size as cell array a, with each value the evaluation of the corresponding string in the cell array.
a = {};
a{1,1} = '0.55';
a{2,1} = '0.25 + 0.50';
a=repmat(a,1000,20); %Make it big for performance evaluation
tic
b1 = cellfun(#eval,a);
toc %0.662187 seconds
Another option is to make a big string expression so that eval is called only once rather than several times due to cellfun internal loop. This is less safe as abnormal values in the cell array a will likely cause the code to crash, while it may simply produce NaN in the code above.
tic
% add a comma separator after each value
strCell = cellfun(#(x) [x ','],transpose(a),'uniformoutput',false);
% add a semicolon separator at the end of each row
strCell(end,:) = cellfun(#(x) [x(1:end-1) ';'], strCell(end,:), 'uniformoutput',false);
% remove the last separator
strCell{end}=strCell{end}(1,end-1);
% evaluate the line
b2=eval(['[' strCell{:} ']']);
toc %0.313738 seconds but sometimes more than 1 seconds
I have a multi-level cell array. The individual levels could be of different size. I am wondering how I can apply cellfunto the lowest level. Imagine the following mulit-level cell array:
a = {randi(10,5,1), randi(5,5,1)}
b = randi(100,5,1,10)
f = {a,b}
Now, I would like to drill down as much as possible and apply cellfun to the deepest level possible of f. At the and of each level, there is a 2D/3D matrix. Let's say, I simply want to add 5 to each value. What's the most efficient way?
Here's the result I am looking for.
[a_nRows, a_nCols, a_nPages] = size(a)
x = cellfun(#plus, f{1}, repmat({5}, a_nRows, a_nCols, a_nPages), 'UniformOutput', false)
y = cellfun(#plus, f(2), {5}, 'UniformOutput', false)
You can use recursion for this.
Firstly, define a function which does one of two things
If the input is a numeric matrix, apply some operation.
If the input is a cell, call this same function with the cell's contents as inputs.
The function would look something like this (defined locally to another function or in its own m file):
function out = myfunc( in, op )
if iscell( in )
out = cellfun( #(x) myfunc(x, op), in, 'UniformOutput', false );
elseif isnumeric( in )
out = op( in );
else
error( 'Cell contents must be numeric or cell!' )
end
end
Then you can call myfunc on your cell. Here is an example similar to yours:
a = {[1 2; 3 4], {eye(2), 10}}; % Nested cell arrays with numeric contents
op = #(M) M + 5; % Some operation to apply to all numeric contents
myfunc( a, op )
% >> ans =
% { [6 7; 8 9], {[6 5; 5 6], 15}}
Directly using your example, the output of myfunc(f, #(M)M+5) is the same as your {x, y{1}} - i.e. the operation op is applied to every cell and nested cell with the result structured the same as the input.
If A is a (x,y) cell array having n cells and each of them is a vector of size (m,n) and of type double.
Example: If A is a 1x2 cell array
A =
[100x1 double] [100x1 double]
Suppose I want to access the first element of each cells at the same time, how can we do so?
Similarly, if we need to access the ith element from every cell, how do we generalise the code?
cell creation with two 1*10 arrays:
A {1} = zeros(1,10) ;
A {2} = zeros (1,10) ;
A =
[1x10 double] [1x10 double]
Adding some data which will be used for fetching later:
A {1}(5) = 5 ;
A {2}(5) = 10 ;
Routine to fetch the data at same index from both arrays inside cell:
cellfun (#(x) x(5),A)
ans =
5 10
As User1551892 suggested, you could use cellfun. Another way is to restruct the cell to a matrix first.
The speed on the operation depends on the number of cells and the size of the matrix within each cell.
% Number of cells
x = 3;
y = 2;
% Size of matrix
m = 1;
n = 100;
% Add some random numbers
A = cell(x,y);
for i = 1:numel(A)
A{i} = round(rand(m,n)*100);
end
% Index to pick in each matrix
idx = 5;
% Convert to matrix
B = [A{:}];
% Pick the number
val = B(idx:(n*m):end);
Doing som tic-toc measurements, the method above is faster for the example values. As long as the one of n or m is small the method is ok.
But if both m and n grows large, cellfun is better (faster)
val = cellfun(#(x) x(idx), A);
An alternative way would be to simply access the cell elements directly , for example we have a cell like you defined
A{1}(1:10) = randi([2 5],1,10);
A{2}(1:10) = randi([2 5],1,10);
now if you want to access the ith elements simply declare i and they will be retrieved in the matrix below
i = 3;
ObsMatrix = [A{1}(i) A{2}(i)]
ObsMatrix =
2 5
If A has unknown number of cell you can simply use a for loop , It will pick ith element from every cell index and put it in ObsMat
i = 3;
for j=1:numel(A)
ObsMat(end + 1) = A{j}(3);
end
cellfun is also a wrapper function for for loop
ObsMat =
2 5
I have a scenario in MATLAB where I would like to evaluate a function for certain parameter values. The parameters are extracted from an arbitrary number of arrays, and each array can have an arbitrary number of elements. I know the number of arrays and the number of elements in them before I call the function.
For example, say I have arrays A = [a1 a2 ... aL], B = [b1 b2 ... bM] and C = [c1 c2 ... cN].
for i = 1:length(A)
for j = 1:length(B)
for k = 1:length(C)
myfunc(A(i), B(j), C(k))
end
end
end
I am considering taking the L elements of A, M elements of B and N elements of C, and flatenning them into a cell array, and iterating with a single for loop over this cell array.
I was wondering if there was a MATLAB function that does something like this ... The result does not have to be a cell array. I want a way to avoid having multiple nested for loops. It is fine for a small number of loops, but as this number grows, it is pretty difficult to read and maintain.
ndgrid can be used to flatten several nested loops into one. It generates all combinations of values (variables aa, bb, cc in the code below), so that a single index (k below) can be used to traverse all combinations. But note that generating all combinations may required a lot of memory, depending on your L, M, N.
[cc, bb, aa] = ndgrid(C, B, A); %// outermost variable should be rightmost here
for k = 1:numel(aa)
myfunc(aa(k), bb(k), cc(k));
end
Thanks to direction from the accepted answer, I made a function that generalizes to any number of arrays. The result is a 2D array of N-tuples - where N is the number of input arrays.
function [Result] = makeTuples(varargin)
nInputArgs = length(varargin);
b = cell(1, nInputArgs);
a = flip(varargin);
[b{:}] = ndgrid(a{:});
bb = flip(b);
nOutputs = length(bb);
N = numel(bb{1});
Result = zeros(N, nInputArgs);
arr = zeros(1,nInputArgs);
for j = 1:N
for k = 1:nOutputs
arr(k) = bb{k}(j);
end
Result(j,:) = arr;
arr = zeros(1,nInputArgs);
end
end
If I have a short list (let's say two or three elements) I would like to have function that split it in several variables. Something like that:
li=[42 43];
[a b]=split(li)
--> a=42
--> b=43
I am looking for some way to make my code shorter in matlab. This one would be nice in some situations For instance:
positions=zeros(10,3);
positions= [....];
[x y z]=split(max(positions,1))
instead of doing:
pos=max(positions,1)
x=pos(1);
y=pos(2);
z=pos(3);
The only way I know of to do this is to use deal. However this works with cell arrays only, or explicit arguments in to deal. So if you want to deal matrices/vectors, you have to convert to a cell array first with num2cell/mat2cell. E.g.:
% multiple inputs
[a b] = deal(42,43) % a=2, b=3
[x y z] = deal( zeros(10,1), zeros(10,1), zeros(10,1) )
% vector input
li = [42 43];
lic = num2cell(li);
[a b]=deal(lic{:}) % unforunately can't do num2cell(li){:}
% a=42, b=43
% matrix input
positions = zeros(10,3);
% create cell array, one column each
positionsc = mat2cell(positions,10,[1 1 1]);
[x y z] = deal(positionsc{:})
The first form is nice (deal(x,y,...)) since it doesn't require you to explicitly make the cell array.
Otherwise I reckon it's not worth using deal when you have to convert your matrices to cell arrays only to convert them back again: just save the overhead. In any case, it still takes 3 lines: first to define the matrix (e.g. li), then to convert to cell (lic), then to do the deal (deal(lic{:})).
If you really wanted to reduce the number of lines there's a solution in this question where you just make your own function to do it, repeated here, and modified such that you can define an axis to split over:
function varargout = split(x,axis)
% return matrix elements as separate output arguments
% optionally can specify an axis to split along (1-based).
% example: [a1,a2,a3,a4] = split(1:4)
% example: [x,y,z] = split(zeros(10,3),2)
if nargin < 2
axis = 2; % split along cols by default
end
dims=num2cell(size(x));
dims{axis}=ones([1 dims{axis}]);
varargout = mat2cell(x,dims{:});
end
Then use like this:
[a b] = split([41 42])
[x y z]= split(zeros(10,3), 2) % each is a 10x1 vector
[d e] = split(zeros(2,5), 1) % each is a 1x5 vector
It still does the matrix -> cell -> matrix thing though. If your vectors are small and you don't do it within a loop a million times you should be fine though.
You can extract the values in the list into different variables with
li = [42 43 44];
tmp = num2cell(li);
[a b c] = deal(tmp{:})
a =
42
b =
43
c =
44
You can manage this in a single expression if you really wanted to:
a = [1, 2, 3, 4]
[b, c, d, e]=feval(#(x)x{:}, num2cell(a))
Result:
b =
1
c =
2
d =
3
e =
4
If you wanted to use this a lot you could quickly make an anonymous function:
expand = #(A) feval(#(x)x{:}, num2cell(A))
[b, c, d, e]=expand(a)
I believe this would work on anything that num2cell will accept, which doesn't even have to be numeric, just needs to be an array, which almost everything in Matlab is.