Filter löschen
Filter löschen

Why Do I Get This Error for This Non-scalar Structure?

15 Ansichten (letzte 30 Tage)
Rightia Rollmann
Rightia Rollmann am 13 Mär. 2017
I have this struct:
A(1).B.C = 'a';
A(2).B.C = 'b';
A(3).B.C = 'a';
When I execute the code below, it works
A(:).B
However, when I execute the code below, it throws an error: “Expected one output from a curly brace or dot indexing expression, but there were 4 results.”
A(:).B.C
WHY do I get this error and MATLAB avoids executing this code?
  1 Kommentar
Stephen23
Stephen23 am 19 Aug. 2022
What do you expect the output to be? All of the field data concatenated together, or places into another container array (e.g. a cell array), or something else? So far you did not explain the desired output.
A(1).B.C = 'a';
A(2).B.C = 'b';
A(3).B.C = 'a';
tmp = [A.B];
{tmp.C} % cell array of fields
ans = 1×3 cell array
{'a'} {'b'} {'a'}
[tmp.C] % concatenate fields horizontally
ans = 'aba'
cat(3,tmp.C) % concatenate fields along some other dimension
ans = 1×1×3 char array
ans(:,:,1) = 'a' ans(:,:,2) = 'b' ans(:,:,3) = 'a'
... etc. etc.

Melden Sie sich an, um zu kommentieren.

Akzeptierte Antwort

Stephen23
Stephen23 am 13 Mär. 2017
Bearbeitet: Stephen23 am 13 Mär. 2017
Comma separated lists are really very simple. You use them all the time. Here is one:
a,b,c,d
There is a comma separated list containing four variables, the variables a, b, c, and d. Every time you write a list of variables separated by commas then you are writing a comma separated list. Most commonly you would write a comma separated list when calling a function or operator:
fun(a,b,c,d)
It is important to note that a comma separated list is not one variable! Sometimes we want to create a comma separated list from one variable: MATLAB has two ways of doing this, these are from a cell array:
cell_array{idx}
ND_struct.field
But both of these are still exactly equivalent to what I wrote at the top: they will generate this:
variable1,variable2,variable3,...
and remember NOT ONE VARIABLE. Therefore the syntax you used:
A(:).B.C
is an error because
A(:).B
creates a comma-separated list, exactly equivalent to this:
A(1).B,A(2).B,A(3).B,...
and it is ambiguous what role the .C should have on the end.
Because this
A(:).B
is exactly equivalent to writing this list of independent variables:
A(1).B,A(2).B,A(3).B...
and yet would you expect to write this list of independent variables:
X,Y,Z.C
and expect it to get the C field of X, Y, and Z?
  2 Kommentare
Rightia Rollmann
Rightia Rollmann am 14 Mär. 2017
This comma-separated list works
A(1).B.C, A(2).B.C, A(3).B.C
Why doesn’t the code below work, and just return values like the code above?
A(:).B.C
Stephen23
Stephen23 am 14 Mär. 2017
Bearbeitet: Stephen23 am 19 Aug. 2022
Because that is consistent with how MATLAB syntax is defined: the end field is not applied to all separate items in the comma separated list. See my last example.
Personally I generally avoid using nested structs for exactly this reason: simple non-scalar structs are easy to use, and the shortcut methods to access their data are simply brilliant. In case I need to use nested structures, a few comma-separated lists and temporary variables can often be used to access their content.

Melden Sie sich an, um zu kommentieren.

Weitere Antworten (3)

Jan
Jan am 14 Mär. 2017
Bearbeitet: Jan am 14 Mär. 2017
Fllowing your comment: A(:).B.C not work?"
Because the operation ".C" is defined for structs and struct arrays, but not for a comma separated list. In A.C the opearion ".C" is applied to a struct array. In A(1).B.C it is applied to a struct. And in A(:).B.C it is tried to be applied to a comma separated list, but this is not defined.
You've struggeled a lot with nested structs. Although this might not be intuitive, Matlab does not have vectorized methods to process nested structs. This requires for loops and there is no way around - except for not using nested structs.
Of course it would be possible to implement this. I thought of doing this in a fast C-mex function, but then I stopped this due to ambiguities: What is the wanted result, when the nested struct contains struct arrays in different levels?
X =A(:).B.C(:).D(:).E
Or if C is a cell containing structs? How sould X look like? A general method must be able to catch this in an intuitive way, and this is not possible in my opinion. Therefore a function for accessing nested structs might look smart at first glance, but I'm convinced that it produces confusion and impedes the debugging. Therefore I stopped the development and decided to rely on stupid loops. Even if this might run some percent slower. Elegance of the the code does not rule, when it causes horrible debugging sessions.

Adam
Adam am 13 Mär. 2017
A(:).B
returns a comma-separated list of (in your example) 3 objects. You can't then further index these by adding .C at the end. Try just putting A(:).B on your command line and you will see why.

Mehmet Burak Ekinci
Mehmet Burak Ekinci am 18 Aug. 2022
If the problem is concatenating array elements of A struct's B.C field.
You could use this custom matlab functions from file exchange. It is for getting values and plotting for nested structure arrays.
For your example:
>>A(1).B.C = 'a';
A(2).B.C = 'b';
A(3).B.C = 'a';
>>getNestedField(A,'B.C')
ans =
3×1 char array
'a'
'b'
'a'
  2 Kommentare
Stephen23
Stephen23 am 19 Aug. 2022
Bearbeitet: Stephen23 am 19 Aug. 2022
The simple MATLAB equivalent without any third-party functions, using two comma-separated lists:
A(1).B.C = 'a';
A(2).B.C = 'b';
A(3).B.C = 'a';
tmp = [A.B];
out = vertcat(tmp.C)
out = 3×1 char array
'a' 'b' 'a'
Mehmet Burak Ekinci
Mehmet Burak Ekinci am 22 Aug. 2022
Bearbeitet: Mehmet Burak Ekinci am 22 Aug. 2022
Thank you for your response.
Out of curiosity i have compared run time of using comma seperated list method you mentioned, with the link i shared.
I would like to share that it is 4 times faster than the link.
For multiple level nested functions, using the comma seperated list method, something like that may be useful:
function structArray = fun(structArray, fieldName)
fieldNameTree = strsplit(fieldName, '.');
% recursively structArray become one level lower struct array, finally it
% will become the values at the desired field name,
% field values of the struct array are concatenated vertically
for i = 1:length(fieldNameTree)
structArray = [structArray.(fieldNameTree{i})]';
end
end

Melden Sie sich an, um zu kommentieren.

Kategorien

Mehr zu Structures finden Sie in Help Center und File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by