Behavior of 'subsref' for arrays of objects - matlab

Imagine a simple array of structures, say:
A = struct('x', {1 2 3}, 'y', {'a' 'b' 'c'});
Asking for a given property for all this array's elements will give something like:
>> A.x
ans =
1
ans =
2
ans =
3
Now, if I explicitly call the subsref function directly on this array, it only retrieves the first element's property:
>> builtin('subsref', A, substruct('.', 'x'))
ans =
1
Why? And is there a possibility to call explicitly another built-in method that will retrieve the property for all the array's elements?

The subsref method can return it but not as a comma separated list the way you get it in the interpreter. It returns them as separate output arguments that means:
>> [a,b,c]=builtin('subsref', A(:), substruct('.', 'x'))
a =
1
b =
2
c =
3
you can capture the output in a cell array if you like
>> [x{1:numel(A)}]=builtin('subsref', A(:), substruct('.', 'x'))
x =
[1] [2] [3]

Related

Find intersection of two cell arrays in mATLAB

I have two cell arrays C & D , they contains numerical data (but some cells are empty) . the data that is inside each cell may be a 2D array, I want to find the intersection of each cell in C with each cell in D
How can I do such thing?
for example : if the size of C & D is 10-by10
C= [ {1 2 } ,{ 3 4},.... etc]
D = [ { 1 34 7} , {2 5},... etc]
Out = c intersect D
out= [ { 1} , {},.... etc]
>> C = {1 [2 3 4; 5 6 7] [] [] 5};
>> D = {1:2 3:5 6 7:9 []};
>> R = cellfun(#(c, d) intersect(c(:), d(:)), C, D, 'uniformoutput', 0);
>> R{:}
ans =
1
ans =
3
4
5
ans =
Empty matrix: 1-by-0
ans =
Empty matrix: 0-by-1
ans =
Empty matrix: 1-by-0
If your data is only numeric (each cell contains a numeric value and empties) I suggest you to change that to a numeric array and use the intersect function. It is easy to represent missing values as NaN.
To convert to double:
tmp = {1, 2, 3, 4, 5, []};
% // Getting rid of the empties
index_empties = cellfun(#isempty, tmp);
tmp(index_empties) = {NaN};
% // converting to double
tmp_double = cellfun(#double, tmp);
Cell values are there to easily create a vector with non-homogeneous data types (Strings and numbers, for example). It is quite common see people using cells to store numbers. While this might be valid in some cases, using cells to store homogeneous data will waste memory and will complicate some operations. For example, you cannot easily sum two cell-vectors with numeric data while summing two double-vectors is trivial.

Matlab - for loop over cell array "foreach"-like syntax loops only over the first element [duplicate]

This question already has answers here:
Is there a foreach in MATLAB? If so, how does it behave if the underlying data changes?
(9 answers)
Closed 8 years ago.
I thought that if I write
for x = cell_array
...
end
then the loop will run over the elements of cell_array, but in the following case it doesn't:
>> tags
tags =
'dset3'
'dset4'
'cpl1'
>> class(tags)
ans =
cell
>> for t = tags
tmp = t{:} %No semicolon: i.e. print it.
end
tmp =
dset3
So it only works for the first element.
What's the problem?
According to the documentation, for x = cell_array will iterate over columns of the cell array.
The reason for the confusion in the question is to do with how the {:} expansion behaves:
>> a = {3;4}
a =
[3]
[4]
>> b = a{:}
b =
3
In the above, a{:} does something akin to typing in a comma-separated list where the elements are the elements of the cell array a. Except not quite! If we write such a list explicitly, we get:
>> c = 3,4
c =
3
ans =
4
Somehow, with the >> b = a{:}, the other elements of a are discarded silently, even if e.g. a = {1 2; 3 4}.
However, in other contexts, a{:} will expand into the full comma-separated list:
>> extra_args = {'*-'; 'linewidth'; 30};
>> plot(1:2, extra_args{:})
>> extra_args = {};
>> plot(1:2, extra_args{:})
This will do what it's intended to do.
There is a nice function built into Matlab called cellfun. It allows you to "do something" with every element in the array in turn - regardless of its shape.
For example:
cellfun(#(x)fprintf(1,'%s',x), cellArray);
will loop over cellArray, and print the string in each cell.
You can also do one of the following things:
for x = cellArray(:)
% do stuff to x
end

Vectorize function that outputs a row using arrayfun, returning a matrix

I'm using Octave and would like to vectorize a function that accepts as input a single real number and outputs a row vector of fixed length. I understand that arrayfun should be able to do this from its unclear documentation. From help arrayfun in Octave 3.2:
If the parameter VAL after a further string input argument
"UniformOutput" is set 'true' (the default), then the named
function FUNC must return a single element which then will be
concatenated into the return value and is of type matrix.
Otherwise, if that parameter is set to `false', then the outputs
are concatenated in a cell array.
It seems however that Matlab's version is more forgiving:
[B1,...,Bm] = arrayfun(func,A1,...,An) calls the function specified by function handle func and passes elements from arrays A1,...,An, where n is the number of inputs to function func. Output arrays B1,...,Bm, where m is the number of outputs from function func, contain the combined outputs from the function calls. The ith iteration corresponds to the syntax [B1(i),...,Bm(i)] = func(A1{i},...,An{i}). The arrayfun function does not perform the calls to function func in a specific order.
It looks like this works in Matlab but not in Octave. Am I correct that this generalization cannot be performed using arrayfun in Octave? Is there some more clever way to achieve this without resorting to unvectorized loops?
For reference, here is my Octave result:
octave:5> nums
nums =
#(c) ([c, c + 2, c + 4])
octave:6> arrayfun(nums,[1,2,3])
error: cellfun: expecting all values to be scalars for UniformOutput = true
error: called from:
error: /opt/local/share/octave/3.2.4/m/general/arrayfun.m at line 168, column 21
octave:6>
Use arrayfun to apply the function, nums to an array [1,2,3]
CellArray = arrayfun(nums, [1,2,3], "UniformOutput", false);
That gives you a cell array. If you want the answer in a matrix, use cell2mat
cell2mat(CellArray);
If your actual nums is more complicated, then we'll need a better example of it to suggest a solution.
The error already suggests how to solve the problem:
arrayfun(nums,[1,2,3],'UniformOutput',false)
There is no difference between Matlab and Octave.
Matlab:
>> nums=#(c) ([c, c + 2, c + 4])
nums =
#(c)([c,c+2,c+4])
EDU>> arrayfun(nums,[1,2,3])
Error using arrayfun
Non-scalar in Uniform output, at
index 1, output 1.
Set 'UniformOutput' to false.
>> arrayfun(nums,[1,2,3],'UniformOutput',false)
ans =
Columns 1 through 2
[1x3 double] [1x3 double]
Column 3
[1x3 double]
Octave:
octave:1> nums=#(c) ([c, c + 2, c + 4])
nums =
#(c) ([c, c + 2, c + 4])
octave:2> arrayfun(nums,[1,2,3])
error: arrayfun: all values must be scalars when UniformOutput = true
octave:2> arrayfun(nums,[1,2,3],'UniformOutput',false)
ans =
{
[1,1] =
1 3 5
[1,2] =
2 4 6
[1,3] =
3 5 7
}
octave:3>
If your function is really that simple, I suggest to use:
nums([1,2,3]')

Passing a function to arrayfun

If I pass an anonymous function to arrayfun as follows:
arrayfun(#(x)sprintf('%.2g\\pi', x/pi), [0 6 7 8], 'uni', 0)
I get the following result:
ans =
'0\pi' '1.9\pi' '2.2\pi' '2.5\pi'
However, if I declare a separate function:
function y = sprint_func_0(x)
sprintf('%.2g\\pi', x/pi)
end
and pass it to arrayfun:
arrayfun(#(x)sprint_func_0(x), [0 6 7 8], 'uni', 0)
The result is:
ans =
0\pi
ans =
1.9\pi
ans =
2.2\pi
ans =
2.5\pi
Why do I get one output in the first case and many outputs in the second case? This is probably stupid, but I can't find the answer anywhere.
In the first case the anonymous function returns a string, so arrayfun returns a cell array of strings.
In the second case the function does not assign a value to the output parameter y (essentially printing the output of sprintf to the command window).
If you modify the function sprint_func_0 to:
function y = sprint_func_0(x)
y = sprintf('%.2g\\pi', x/pi); %// Note the assignment to y
end
you should get the same result.

find NaN values is cell array

lets assume I have the following array:
a = {1; 'abc'; NaN}
Now I want to find out in which indices this contains NaN, so that I can replace these with '' (empty string).
If I use cellfun with isnan I get a useless output
cellfun(#isnan, a, 'UniformOutput', false)
ans =
[ 0]
[1x3 logical]
[ 1]
So how would I do this correct?
Indeed, as you found yourself, this can be done by
a(cellfun(#(x) any(isnan(x)),a)) = {''}
Breakdown:
Fx = #(x) any(isnan(x))
will return a logical scalar, irrespective of whether x is a scalar or vector.
Using this function inside cellfun will then erradicate the need for 'UniformOutput', false:
>> inds = cellfun(Fx,a)
inds =
0
0
1
These can be used as indices to the original array:
>> a(inds)
ans =
[NaN]
which in turn allows assignment to these indices:
>> a(inds) = {''}
a =
[1]
'abc'
''
Note that the assignment must be done to a cell array itself. If you don't understand this, read up on the differences between a(inds) and a{inds}.
I found the answer on http://www.mathworks.com/matlabcentral/answers/42273
a(cellfun(#(x) any(isnan(x)),a)) = {''}
However, I do not understant it...
a(ind) = [] will remove the entries from the array
a(ind)= {''} will replace the NaN with an empty string.
If you want to delete the entry use = [] instead of = {''}.
If you wanted to replace the NaNs with a different value just set it equal to that value using curly braces:
a(ind) = {value}