How to access a field of a struct by indexing?

I have a 1-by-1 struct that possesses 3 fields named B, C, and D. Is there any way to call D by its index (i.e., D is the third field of struct A, so call the third field of struct A without mentioning the field name D) rather than its name (i.e, A.D)?
A.B = 1;
A.C = 2;
A.D = 3;

1 Commento

Stephen23
Stephen23 il 26 Feb 2017
Modificato: Stephen23 il 26 Feb 2017
@Rightia Rollmann: you might like to consider using a non-scalar structure, which lets you use indexing to access structures:

Accedi per commentare.

 Risposta accettata

Jan
Jan il 26 Feb 2017
Modificato: Jan il 26 Feb 2017
A_cell = struct2cell(A);
D = A_cell{3}
Keep in mind that the order of the fields of structs is not necessarily constant:
A.B = 1;
A.C = 2;
A.D = 3;
B.B = 1;
B.D = 3;
B.C = 2;
isequal(A, B) % >> TRUE!

4 Commenti

So isn't there any direct way (without converting to cell array) to access a field by indexing?
Jan
Jan il 26 Feb 2017
Modificato: Jan il 26 Feb 2017
No, there is no way. The idea of structs is to access the fields by their name. If addressing by the index is wanted, cell arrays are the best type for representing the data.
You can hide the indirection through the cell inside a function:
function Data = GetFieldByIndex(S, n)
C = struct2cell(S);
Data = D{n}; % Care for struct arrays!
But consider the above warning:
A.B = 1; A.C = 2; A.D = 3;
B.B = 1; B.D = 3; B.C = 2;
isequal(A, B) % TRUE
isequal(GetFieldByIndex(A, 2), GetFieldByIndex(B, 2)) % FALSE
I thought of publishing a fast C-Mex function for GetFieldByIndex, but decided against it, because this would mix the ideas of structs and fields and the resulting code would be less clear.
If struct2cell results in copying the data in the structure, Guillaume's answer below is superior.
struct2cell creates shared-data-copies of the field variables. So, while there is overhead involved in creating the variable header info, the data itself is not copied.

Accedi per commentare.

Più risposte (1)

Yes, there is a way to get the nth field directly:
fns = fieldnames(A);
A.(fns{3})
But be aware that the order of the fields depends solely on the order in which they were created. As Jan pointed out, two structures may be indentical, yet have different field order.
Usually, you would only access fields by their index when you're doing some structure metaprogramming

5 Commenti

This is the correct answer. Further elaborated in order to change all fields:
for n = 1:numel(fieldnames(tempanchors))
names = fieldnames(tempanchors)
tempanchors.(names{n}).status = 1
end
This snippet takes a struct `tempanchors` and adds a field status with value 1 to every field of tempanchors.
@Eric Mink why do you need to add new field, "status" = 1?
@Guillaume, how do you make it shorter, one line only?
I mean something like this
A.(fieldnames(A){3}) % it doesn't work
%Error:
%Indexing with parentheses '()' must appear as the last operation of a valid indexing expression.
Edit, I found the solution from stackoverflow
A.(subsref(fieldnames(A),substruct('{}',{3})))
To add on to this question, can someone explain why A.(subsref(fieldnames(A),substruct('{}',{:}))) would not work?
@Vaishnavi: One reason that doesn't work is that you need single quotes around the colon in substruct. But even then, it may not do what you expect. Here's what it does (gets the value of the first field of A):
A = struct('field1',1,'field2',2)
A = struct with fields:
field1: 1 field2: 2
A.(subsref(fieldnames(A),substruct('{}',{':'})))
ans = 1
In order to know whether that "works", one would need to know what you expected it to do.

Accedi per commentare.

Categorie

Richiesto:

il 26 Feb 2017

Commentato:

il 19 Dic 2023

Community Treasure Hunt

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

Start Hunting!

Translated by