Convert Matlab struct array to cell array - matlab

Can a Matlab struct array be converted to a cell array without iterating through the array?
I want each struct in the struct array to become one cell in the cell array. The command struct2cell doesn't seem to do it as it breaks out each field in the struct into a separate cell.
This has been posted to:
Convert Matlab struct array to cell array
http://groups.google.com/forum/#!topic/comp.soft-sys.matlab/xIOTcs5HPeg

Try num2cell:
myStructCell = num2cell(myStruct);
For example:
>> myStruct(1).name = 'John';
>> myStruct(2).name = 'Paul';
>> myStruct
myStruct =
1x2 struct array with fields:
name
>> myStructCell = num2cell(myStruct)
myStructCell =
[1x1 struct] [1x1 struct]
>> myStructCell{1}
ans =
name: 'John'
>> myStructCell{2}
ans =
name: 'Paul'
>> myStructCell{2}.name
ans =
Paul

Actually, I don't think that what I'm trying to do is necessary. Let me explain, in case it saves someone else from going down the same path.
The motivation for the above is that I want to extract a certain subfield from all structures in the struct array and have it in the form of a comma separated list:
myStruc(1).fieldX.subfieldA, ...
myStruc(2).fieldX.subfieldA, ...
myStruc(3).fieldX.subfieldA
I knew that I could generate a comma separated list by indexing into all cells into a 1D cell array via myCellArray{:}.
However, I found that there was actually an entire help page entitled "Comma-Separated Lists" showing that structs behave in the same way. So the above comma separated list is equal to myStruc(:).fieldX.subfieldA.
In fact, converting the struct array into a cell array wouldn't have worked because you can't use dot-indexing to access the fields after curly-brace indexing of the cell array. For example, if there was a vectorized way to convert myStruct(i) into myCell(i), I was hoping to be able to generate
myCellArray{1}.fieldX.subfieldA, ...
myCellArray{2}.fieldX.subfieldA, ...
myCellArray{3}.fieldX.subfieldA
via the expression myCell{:}.fieldX.subfieldA. The dot-indexing after the curly braces is a syntax error.
Lesson learned: Use struct array indexing directly to enable access to the struct fields & subfields.
***** CAVEAT *****
I only tested the generation of comma separated lists using multiple levels of dot-indexing combined with a scalar numerical array index, e.g., myCellArray{2}.fieldX.subfieldA. It doesn't work when with a vector numerical index in place of the scalar value 2, i.e., Matlab cannot handle myCellArray{:}.fieldX.subfieldA or myCellArray{2:3}.fieldX.subfieldA.
Oh well. :(

Related

Convert cell array with sub cells into numeric array

Assume I have A that is a 64x1 cell array.
Each of the 64 cells contains another cell with a string (which is a number, i.e. 11)
A{1, 1}{1, 1} = ’11’ (char)
A{2, 1}{1, 1} = ’13’ (char)
How can I create a numeric array such as
A = [11,13,…]
The cell2mat function seems to work only on “first level” cell array:
cell2mat does not support cell arrays containing cell arrays or objects.
You can use cellfun to convert the contents of each individual cell in A to doubles.
A{1, 1}{1, 1} = '11';
A{2, 1}{1, 1} = '13';
A_array = cellfun(#(a) str2double(a), A)
Breakdown of the function: #(a) passes the contents of each cell of A to the variable a, which can be converted to doubles using str2double(a).
It's quite simple, however you need split it to two steps. Let's assume we have simple 1x4 string array:
A= {'11','13','15','17'};
To convert it you need store the content in temporary variable S, then use sscanf to generate final result:
S = sprintf('%s ', A{:});
Result = sscanf(S, '%f')
The only problem is that it will be column vector. If you need it in a row, you can just transpose(Results).
I'm not sure I entirely understand your question. If I've got it right, you're talking about a cell array like asd below
asd=cell(61,1);
for ii=1:64
asd{ii}={['test',num2str(ii)]}
end
If I understand your goal correctly, I think the following does it somewhat neatly
A=char([asd{:}])
Then if you want to convert the strings to numbers (which wouldn't work for my test, but might for your strings), just use str2num on this new vector
Transform A into a comma-separated list of cells, then horizontally concatenate these cells and finally apply str2double;
A = str2double([A{:}]);

MATLAB extract field from struct in a vector array

I got the following Problem: I got a struct Array and want to extract one field from that struct in a vector.
The struct has 5 fields, one which is called "name". How can I get These in a vector?
The answer by dfri works but requires MATLAB Mapping Toolbox. You can use
{yourStruct.name} to get them as a cell array or [yourStruct.name] to get them as an array:
>> A(1).name='a';
>> A(2).name='b';
>> A(3).name='c';
>> {A.name}
ans =
'a' 'b' 'c'
or,
>> A(1).num=10;
>> A(2).num=5;
>> A(3).num=25;
>> [A.num]
ans =
10 5 25
You can make use of the extractfield method:
yourNameFieldsAsArray = extractfield(yourStruct, 'name')
Where yourNameFieldsAsArray will be a cell array if the name field holds e.g. character/string values, or a regular value array if name field just hold, say, integers.

How to get a list of all structs where struct.somearray contains an element from a query array

As input to a function, I am getting an array of target elements, T, and an array of structs S where each one has a .elems field, which is a list of integers (elements).
I'm sure there's a simple way to do this in Matlab. How do I get the indices i of all structs where a specific element t of T is in S(i).elems contains t?
So I think you'll need to do this with an arrayfun. I did:
S = ... (1-by-N array of structs);
T = ... (1-by-K array of numbers);
indices = find(arrayfun(#(i)any(ismember(T, S(i).elems)), 1:numel(S)));
any(ismember(T, S(i)elems)) tests is any of the things in T are in S(i).elems. The arrayfun repeats this for each struct in S. find extracts indices from the logical array that is returned by the arrayfun.

Iterating through struct fieldnames in MATLAB

My question is easily summarized as: "Why does the following not work?"
teststruct = struct('a',3,'b',5,'c',9)
fields = fieldnames(teststruct)
for i=1:numel(fields)
fields(i)
teststruct.(fields(i))
end
output:
ans = 'a'
??? Argument to dynamic structure reference must evaluate to a valid field name.
Especially since teststruct.('a') does work. And fields(i) prints out ans = 'a'.
I can't get my head around it.
You have to use curly braces ({}) to access fields, since the fieldnames function returns a cell array of strings:
for i = 1:numel(fields)
teststruct.(fields{i})
end
Using parentheses to access data in your cell array will just return another cell array, which is displayed differently from a character array:
>> fields(1) % Get the first cell of the cell array
ans =
'a' % This is how the 1-element cell array is displayed
>> fields{1} % Get the contents of the first cell of the cell array
ans =
a % This is how the single character is displayed
Since fields or fns are cell arrays, you have to index with curly brackets {} in order to access the contents of the cell, i.e. the string.
Note that instead of looping over a number, you can also loop over fields directly, making use of a neat Matlab features that lets you loop through any array. The iteration variable takes on the value of each column of the array.
teststruct = struct('a',3,'b',5,'c',9)
fields = fieldnames(teststruct)
for fn=fields'
fn
%# since fn is a 1-by-1 cell array, you still need to index into it, unfortunately
teststruct.(fn{1})
end
Your fns is a cellstr array. You need to index in to it with {} instead of () to get the single string out as char.
fns{i}
teststruct.(fns{i})
Indexing in to it with () returns a 1-long cellstr array, which isn't the same format as the char array that the ".(name)" dynamic field reference wants. The formatting, especially in the display output, can be confusing. To see the difference, try this.
name_as_char = 'a'
name_as_cellstr = {'a'}
You can use the for each toolbox from http://www.mathworks.com/matlabcentral/fileexchange/48729-for-each.
>> signal
signal =
sin: {{1x1x25 cell} {1x1x25 cell}}
cos: {{1x1x25 cell} {1x1x25 cell}}
>> each(fieldnames(signal))
ans =
CellIterator with properties:
NumberOfIterations: 2.0000e+000
Usage:
for bridge = each(fieldnames(signal))
signal.(bridge) = rand(10);
end
I like it very much. Credit of course go to Jeremy Hughes who developed the toolbox.

MATLAB "bug" (or really weird behavior) with structs and empty cell arrays

I have no idea what's going on here. I'm using R2006b. Any chance someone out there with a newer version could test to see if they get the same behavior, before I file a bug report?
code: (bug1.m)
function bug1
S = struct('nothing',{},'something',{});
add_something(S, 'boing'); % does what I expect
add_something(S.something,'test'); % weird behavior
end
function add_something(X,str)
disp('X=');
disp(X);
disp('str=');
disp(str);
end
output:
>> bug1
X=
str=
boing
X=
test
str=
??? Input argument "str" is undefined.
Error in ==> bug1>add_something at 11
disp(str);
Error in ==> bug1 at 4
add_something(S.something,'test');
It looks like the emptiness/nothingness of S.something allows it to shift the arguments for a function call. This seems like Very Bad Behavior. In the short term I want to find away around it (I'm trying to make a function that adds items to an initially empty cell array that's a member of a structure).
Edit:
Corollary question: so there's no way to construct a struct literal containing any empty cell arrays?
As you already discovered yourself, this isn't a bug but a "feature". In other words, it is the normal behavior of the STRUCT function. If you pass empty cell arrays as field values to STRUCT, it assumes you want an empty structure array with the given field names.
>> s=struct('a',{},'b',{})
s =
0x0 struct array with fields:
a
b
To pass an empty cell array as an actual field value, you would do the following:
>> s = struct('a',{{}},'b',{{}})
s =
a: {}
b: {}
Incidentally, any time you want to set a field value to a cell array using STRUCT requires that you encompass it in another cell array. For example, this creates a single structure element with fields that contain a cell array and a vector:
>> s = struct('strings',{{'hello','yes'}},'lengths',[5 3])
s =
strings: {'hello' 'yes'}
lengths: [5 3]
But this creates an array of two structure elements, distributing the cell array but replicating the vector:
>> s = struct('strings',{'hello','yes'},'lengths',[5 3])
s =
1x2 struct array with fields:
strings
lengths
>> s(1)
ans =
strings: 'hello'
lengths: [5 3]
>> s(2)
ans =
strings: 'yes'
lengths: [5 3]
ARGH... I think I found the answer. struct() has multiple behaviors, including:
Note If any of the values fields is
an empty cell array {}, the MATLAB
software creates an empty structure
array in which all fields are also
empty.
and apparently if you pass a member of a 0x0 structure as an argument, it's like some kind of empty phantom that doesn't really show up in the argument list. (that's still probably a bug)
bug2.m:
function bug2(arg1, arg2)
disp(sprintf('number of arguments = %d\narg1 = ', nargin));
disp(arg1);
test case:
>> nothing = struct('something',{})
nothing =
0x0 struct array with fields:
something
>> bug2(nothing,'there')
number of arguments = 2
arg1 =
>> bug2(nothing.something,'there')
number of arguments = 1
arg1 =
there
This behaviour persists in 2008b, and is in fact not really a bug (although i wouldn't say the designers intended for it):
When you step into add_something(S,'boing') and watch the first argument (say by selecting it and pressing F9), you'd get some output relating to the empty structure S.
Step into add_something(S.something,'test') and watch the first argument, and you'd see it's in fact interpreted as 'test' !
The syntax struct.fieldname is designed to return an object of type 'comma separated list'. Functions in matlab are designed to receive an object of this exact type: the argument names are given to the values in the list, in the order they are passed. In your case, since the first argument is an empty list, the comma-separated-list the function receives starts really at the second value you pass - namely, 'test'.
Output is identical in R2008b:
>> bug1
X=
str=
boing
X=
test
str=
??? Input argument "str" is undefined.
Error in ==> bug1>add_something at 11
disp(str);
Error in ==> bug1 at 4
add_something(S.something,'test'); % weird behavior