it-swarm.com.de

Wie greife ich dynamisch auf Strukturfelder zu?

Ich habe eine Struktur mit vielen Feldern, die Vektoren unterschiedlicher Länge sind. Ich möchte in einer Schleife auf die Felder zugreifen, in der Reihenfolge. Ich habe getfield wie folgt ausprobiert, aber MATLAB gefällt das nicht. Wie kann ich das machen? 

S = struct('A', [1 2], 'B',[3 4 5]);
SNames = fieldnames(S);
for loopIndex = 1:2
  field = getfield(S, SNames(loopIndex));
  %do stuff w/ field
end
??? Index exceeds matrix dimensions

Ich verwende Strukturen in erster Linie, weil ein Array Probleme mit den unterschiedlichen Feldlängen haben würde. Gibt es eine bessere Alternative dazu?

31
marciovm

Versuchen Sie eine dynamische Feldreferenz, bei der Sie einen String in die Klammern setzen, wie in der Zeile, die stuff definiert.

S = struct('A', [1 2], 'B',[3 4 5]); 
SNames = fieldnames(S); 
for loopIndex = 1:numel(SNames) 
    stuff = S.(SNames{loopIndex})
end 

Ich stimme mit Steve und Adam überein. Verwenden Sie Zellen. Diese Syntax ist jedoch für Menschen in anderen Situationen geeignet!

42
MatlabDoug

Ich möchte hier drei Punkte ansprechen:

  • Der Grund, warum Sie einen Fehler in Ihrem obigen Code erhalten, ist, wie Sie SNames indizieren. Die Funktion fieldnames gibt ein Zellenfeld von Zeichenfolgen zurück. Daher müssen Sie content indexing (d. H. Geschweifte Klammern) verwenden, um auf die Zeichenfolgenwerte zuzugreifen. Wenn Sie die vierte Zeile in Ihrem Code folgendermaßen ändern:

    field = getfield(S, SNames{loopIndex});
    

    dann sollte Ihr Code ohne Fehler funktionieren.

  • Wie von MatlabDoug vorgeschlagen, können Sie dynamische Feldnamen verwenden, um zu vermeiden, dass Sie getfield verwenden müssen (was meiner Meinung nach saubereren Code ergibt).

  • Der Vorschlag von Adam , um ein Zellenarray anstelle einer Struktur zu verwenden, stimmt genau. Dies ist im Allgemeinen der beste Weg, um eine Reihe von Arrays unterschiedlicher Länge in einer einzigen Variablen zu erfassen. Ihr Code würde am Ende so aussehen:

    S = {[1 2], [3 4 5]};        % Create the cell array
    for loopIndex = 1:numel(S)   % Loop over the number of cells
      array = S{loopIndex};      % Access the contents of each cell
      % Do stuff with array
    end
    
16
gnovice

Der Getfield-Ansatz ist in Ordnung (obwohl mir MATLAB momentan nicht zur Verfügung steht und mir nicht klar ist, warum dies nicht funktioniert).

Für eine alternative Datenstruktur möchten Sie möglicherweise auch MATLAB-Zellenarrays betrachten. Sie können auch Vektoren unterschiedlicher Länge speichern und indizieren.

5
Adam Holmberg

Sie können Doppelpunktnotation verwenden, um Indizes zu vermeiden:

S = struct('A', [1 2], 'B',[3 4 5]); 
SNames = fieldnames(S); 
for SName = [SNames{:}]
    stuff = S.(SName)
end
3
Niver

Wenn Sie eine Struktur verwenden müssen, fand ich es sehr gut, zuerst in eine Zelle umzuwandeln, dann haben Sie das Beste aus beiden Welten. 

S = struct('A', [1 2], 'B',[3 4 5]); 
S_Cell = struct2cell(S);
%Then as per gnovice
for loopIndex = 1:numel(S_Sell)   % Loop over the number of cells
    array = S{loopIndex};         % Access the contents of each cell
    %# Do stuff with array
end

Ich habe etwas Ähnliches für etwas verwendet, das in einer Struktur generiert wurde, und dann musste ich wie eine Matrix darauf zugreifen. In diesem Fall war es so einfach wie 

M = cell2mat(struct2cell(S));

Um es in eine Matrix umzuwandeln

2
dabhand

Um dem Mix eine weitere Antwort hinzuzufügen. Ich mag die Lösung von @Niver, aber sie funktioniert nur für Felder mit Einzelbuchstaben. Die Lösung, die ich verwendete, war:

S = struct('A', [1 2], 'B',[3 4 5], 'Cee', [6 7]); 
for SName = fieldnames(S)'
    stuff = S.(SName{1})
end

for durchläuft die Spalten eines Zellen-Arrays (daher wird die Transponierung bei fieldnames(S)' durchlaufen. Für jede Schleife wird SName zu einem 1x1-Zellen-Array. Daher verwenden wir die Inhaltsindizierung, um auf das erste und einzige Element mit SName{1} zuzugreifen.

0
sclarke81