I'm trying to assign a cell array to a subset of another cell array, like
data_date1 = '08/15/2003';
data_date2 = '08/16/2003';
data_date3 = '08/17/2003';
num1 = 56;
num2 = 23;
num3 = 2;
cell_1={data_date1, num1; data_date2, num2};
array=cell(3,1)
array{1:2} = cell_1 % problem line
array{3} = {data_date3, num3}
For context, the cell_1 array is the output of another function, and I'm trying to fill array in a loop in another function.
What's the proper method for this?
To copy cell array elements from one cell array to another without having to access the content of the element you can use the standard matrix indexing syntax, which uses the brackets (i,j) instead of the curly braces {i,j}.
let M be a cell array:
M(i,j) return a 1x1 cell, copy of the (i,j) element of M
M{i,j} return the content of the (i,j)th element of M. This could be of any type, depending on what the cell content was.
Cell array as a standard array
So in your case you can assign subarray to a larger array, but you just have to watch your indexing (the size in all dimensions should be correct).
So if you declare a 3x2 cell array:
array=cell(3,2)
Then you can assign your 2x2 sub array to it, if you have the address right:
>> array(1:2,:) = cell_1
array =
'08/15/2003' [56]
'08/16/2003' [23]
[] []
And then add your last elements:
>> array(3,:) = {data_date3, num3}
array =
'08/15/2003' [56]
'08/16/2003' [23]
'08/17/2003' [ 2]
This way treat your array like an nxm standard array, just consider the cell type like a specific type (like you would have double or uint8 array) without having to know the type of the data they contain inside.
Nested Cell array
Cell array have this capacity to be nested. So a single cell of a cell array could contain another whole cell array (where each cell could contain cell array etc ... although I wouldn't recommend nesting too deep).
In this configuration, you final array could be as you defined it, a 3x1 cell array, where each cell would contain another 1x2 cell array. You can also assign subarray to this type, but again the sizes of source and destinations have to match. So if you prefer this form, you would have to define your cell_1 slightly differently:
>> cell_1= { {data_date1, num1} ; { data_date2, num2} }
cell_1 =
{1x2 cell}
{1x2 cell}
Note the nesting of cell array into the larger cell array, in order to have a 1x2 subarray, which you can now assign to your main array:
>> array=cell(3,1) ;
array(1:2) = cell_1
array =
{1x2 cell}
{1x2 cell}
[]
Now to add the last element you have two different ways but you need to be careful:
array(3) = { {data_date3, num3} } %// assign a 1x2 sub array to the 3rd element of "array"
array{3} = {data_date3, num3} %// set the content of the 3rd element of "array" as a 1x2 cell array
These two lines are equivalent, they produce the same result. You can do either or, depending on the style you prefer (or may be forced by the shape your data are coming in).
There is error is because you cannot use indexing with cell array like that. Either you must do like:
array{1} = cell_1;
array{2} = cell_1;
array{3} = {data_date3, num3};
or you can try repmat (no need initialization array = cell(3,1)), though I don't know how long is your array:
array = repmat({cell_1}, 2, 1);
% or: array = {cell_1; cell_1}
array{3} = {data_date3, num3};
Another way if array is short:
array = {cell_1; cell_1; {data_date3, num3}};
Related
I have a cell array (let's say size 10) where each cell is a structure with the same fields. Let's say they all have a field name x.
Is there a way to retreive in a vector the value of the field x for all the structure in the cell array? I would expect the function to return a vector of size 10 with in position 1, the value of the field x of the structure in cell 1 etc etc...
EDIT 1:
The structure in the cell array have 1 field which is the same for all but some others which are different.
First convert your cell array of structures, c, (with identical field names in the same order) to a structure array:
c = cell2mat(c)
Then, depending on the data types and sizes of the elements of the field, you may be able to use
[c.x]
to extract your vector of field x values in the "standard" way.
It is also possible that you can skip the conversion step and use cellfun(#(e)e.x, c) to do the extraction in one go.
The below code creates a cell array of structures, and extracts field 'x' of each structure to a vector v.
%create a cell array of structures
s1.a = 'hello';
s1.x = 1;
s2.a = 'world';
s2.x = 2;
c{1} = s1;
c{2} = s2;
v = zeros(1,2);
%extract to vector
for idx=1:size(c,2)
v(1,idx) = c{idx}.x;
end
Let's say you have
c = {s1, s2, s3, ...., sn};
where common field is 'field_1', then you have two options
Use cell2mat.
cc = cell2mat(c); % which converts your cell array of structs into an array of structs
value = [cc.field_1]; % if values are number
or
value = {cc.field_1}; % if values are characters, for example
Another option is to use cellfun.
If the field values are characters, you should set "UniformOutput" to "false"
value = cellfun(#(x) x.field_1, c, 'UniformOutput', false)
The first option is better. Also, try to avoid using cell/cellfun/arrayfun whenever you can, vectors are way faster and even a plain for loop is more effecient
In Matlab, we use textscan to get a cell array from a file or somewhere. But the behavior of the cell array is so strange.
There is the sample code:
>> str = '0.41 8.24 3.57 6.24 9.27';
>> C = textscan(str, '%3.1f %*1d');
>> C
C =
[5x1 double]
We can know that C is a cell array of size 5 * 1. When I use C{1}, C{1}{1} and C(1). I get the following result:
>> C{1}
ans =
0.4000
8.2000
3.5000
6.2000
9.2000
>> C{1}{1}
Cell contents reference from a non-cell array object.
>> C(1)
ans =
[5x1 double]
Why I cannot use C{1}{1} to get the element from the cell array ? Then how can I get the elements from that cell array ?
An example I found on the Internet is :
%% First import the words from the text file into a cell array
fid = fopen(filename);
words = textscan(fid, '%s');
%% Get rid of all the characters that are not letters or numbers
for i=1:numel(words{1,1})
ind = find(isstrprop(words{1,1}{i,1}, 'alphanum') == 0);
words{1,1}{i,1}(ind)=[];
end
As words{1,1}{i,1}(ind)=[] show, what is the mechanism of using {}?
Thanks
Then how can I get the elements from that cell array ?
C = C{:}; % or C = C{1};
Access values by C(1), C(2) and so on
There is a slightly different syntax for indexing into cell arrays and numerical arrays. Your output
>> C
C =
[5x1 double]
is telling you that what you have is a 1x1 cell array, and in that 1 cell is a 5x1 array of doubles. Cell arrays are indexed into with {}, while 'normal' arrays are indexed into with ().
So you want to index into the first element of the cell array, and then index down to the first value in the 5x1 array of doubles using C{1}(1). To get the second value - C{1}(2), and so forth.
If you're familiar with other programming languages, cell arrays are something like arrays of pointers; the operator A(n) is used to get the nth element of the array A, while A{n} gets the object pointed to by the nth element of the array A (or 'contained in the nth cell of cell array A'). If A is not a cell array, A{n} fails.
So, knowing that C is a cell array, here's why you got what you got in the cases you tried -
C{1} returns the 5x1 double array contained in the first cell of C.
C{1}{1} gets the object (call it B) contained in the first cell of C, and then tried to get the object contained in the first cell of B. It fails because B is not a cell array, it is a 5x1 double array.
And C(1) returns the first element of C, which is a single cell containing a 5x1 double array.
But C{1}(1) would get you the first element of the 5x1 array contained in the first cell of C, which is what you are looking for. As #Cheery above me noted, it's probably easier, instead of writing C{1}(1), C{1}(2), ... to remove the 'cell-level' indexing by setting C=C{1}, which means C is now a 5x1 double array, and you can get the elements of it using C(1), C(2), ... Hope that makes sense!
The following line works
array ={'a','b'; 1,2};
but
num = [1,2];
array ={'a','b'; num};
doesn't.
I also tried
array ={'a','b'; mat2cell(num)};
and
array ={'a','b'; num2cell(num)};
but neither of them worked. How can I produce a 2x2 cell matrix containing a, b, 1 and 2?
Use concatenation:
array = [{'a','b'}; num2cell(num)]
Or extend the cell array as follows:
array = {'a','b'};
array(end+1,:) = num2cell(num);
Here's code that creates an example cell array for this question:
mycell = cell([5,1]);
for i = 1 : size(mycell)
mystruct = struct();
mycell{i} = mystruct;
mycell{i}.field1 = i;
end
I expected mycell{:}.field1 to do what I want, but it gives an error. I can use the following for loop:
for i = 1 : size(mycell)
mycell{i}.field1
end
but I'd prefer a simpler or more elegant solution as a want to use all the elements of mycell.field1 as the y-variables in a plot. Any ideas?
Two possible solutions:
First:
If all the structs in your cell array have the same fields than you can:
mycell = [ mycell{:} ]; % convert cell array to struct array
y = [ mycell(:).filed1 ]; % get the values
Second:
Another method uses cellfun
y = cellfun( #(x) x.field1, mycell );
assuming all mycell{ii}.filed1 are scalars, otherwise you'll need to add 'UniformOutput', false to the cellfun.
note: in case some fields are empty ([]) these methods might not work as expected.
One small remark:
it is not a good practice to use i and j as variables in Matlab.
I have a cell array allData which is Nx1. Each cell contains a structure with a names property (the name is a custom object, but think of it as a cell array of strings if you like). I would like to create a single cell array that contains all of the names. For example, if N=3, so that allData is a 3x1 cell array, then the following would accomplish my goal:
A = allData{1};
B = allData{2};
C = allData{3};
allNames = [A.names B.names C.names];
The problem with this approach is that N is large and changes depending on the input, so I'm hoping that there is a clever way to do this using cellfun, but everything that I've tried fails (e.g. it doesn't work to do allNames = [cellfun(#(x) {x.names}, allData)];).
UPDATE: Thanks to the suggested solutions, I can get everything into one cell array where each cell contains a cell array. My goal here is to concatenate these. More or less, what I have is:
{A.names B.names C.names}
and what I want and cannot seem to get is
{A.names{1} A.names{2} ... A.names{end} B.names{1} ... B.names{end} ...}
SOLUTION:
I needed pieces of each answer below, so here's the solution that worked for me:
from Andrew Lazarus:
allNames = arrayfun(#(x) x.name, [allData{:}], 'UniformOutput', false);
then, from gnovice:
allNames = vertcat(allNames{:});
Thanks to both!!
There are a few more details about your cell contents that would be needed for a more general solution, but if the names property always returns a cell array of strings, and if your structures are all scalars (i.e. 1-by-1 structure arrays), then the following solution using CELLFUN, CHAR, and CELLSTR will give you an N-by-1 cell array of strings allNames containing all of your names:
allNames = cellfun(#(x) {char(x.names)},allData);
allNames = cellstr(char(allNames{:}));
And here's an example where allData contains three different structures:
>> allData{1} = struct('names',{{'hello'}},'junk',1:3);
>> allData{2} = struct('names',{{'hi' 'yo' 'hey' 'whassup'}});
>> allData{3} = struct('names',{{'howdy';'aloha'}},'junk',4);
>> allNames = cellfun(#(x) {char(x.names)},allData);
>> allNames = cellstr(char(allNames{:}))
allNames =
'hello'
'hi'
'yo'
'hey'
'whassup'
'howdy'
'aloha'
EDIT:
Generalizing to the case where the names property returns a cell array of objects, not necessarily strings, you can try this solution which reshapes each cell array into an M-by-1 cell array, then vertically concatenates all of them into an N-by-1 cell array of objects:
allNames = cellfun(#(x) {reshape(x.names,[],1)},allData);
allNames = vertcat(allNames{:});
Or, if you would rather end up with a 1-by-N cell array of objects, you can do this:
allNames = cellfun(#(x) {reshape(x.names,1,[])},allData);
allNames = [allNames{:}];
Try this
allNames = arrayfun(#(x) x.name, [allData{:}], 'UniformOutput', false)
Omit the UniformOutput vararg for straight concatenation. This gives a cell output.