2008-09-02 19 views
21

Ich möchte zwei Strukturen mit unterschiedlichen Feldern Namen kombinieren.Wie können zwei Strukturen in MATLAB effizient kombiniert werden?

Zum Beispiel beginnend mit:

A.field1 = 1; 
A.field2 = 'a'; 

B.field3 = 2; 
B.field4 = 'b'; 

würde ich gerne haben:

C.field1 = 1; 
C.field2 = 'a'; 
C.field3 = 2; 
C.field4 = 'b'; 

Gibt es eine effizientere Art und Weise "Feldnamen" und eine for-Schleife als die Verwendung von?

EDIT: Nehmen wir an, dass im Fall von Feldnamen Konflikte geben wir A.

Antwort

15

ohne Kollisionen können Sie

M = [fieldnames(A)' fieldnames(B)'; struct2cell(A)' struct2cell(B)']; 
C=struct(M{:}); 

tun, und das ist ziemlich effizient. Allerdings struct Fehler bei doppelten Feldnamen, und Vorabprüfung für sie mit unique tötet Leistung bis zu dem Punkt, dass eine Schleife besser ist. Aber hier ist, wie es aussehen würde:

M = [fieldnames(A)' fieldnames(B)'; struct2cell(A)' struct2cell(B)']; 

[tmp, rows] = unique(M(1,:), 'last'); 
M=M(:, rows); 

C=struct(M{:}); 

Sie könnten in der Lage, eine Hybrid-Lösung zu machen, indem keine Konflikte übernehmen und mit einem try/catch um den Anruf zu struct zu graziös auf den Konflikt abbauen Sachbearbeitung.

+0

Die erste Lösung konnte von "cell2struct" in einen einzigen Liner umgewandelt werden. Ich weiß aber nicht, wie das funktioniert. –

2

In C kann eine Struktur eine andere Struktur als eines ihrer Mitglieder haben. Während dies nicht genau das ist, was Sie fragen, könnten Sie entweder mit einer Situation enden, in der eine Struktur eine andere enthält, oder eine Struktur enthält zwei Strukturen, die beide Teile der gewünschten Information enthalten.

psuedocode: ich erinnere mich nicht an die tatsächliche Syntax.

A.field1 = 1; 
A.field2 = 'a'; 
A.field3 = struct B; 

auf Zugang: A.field3.field4;

oder etwas ähnliches.

Oder man könnte Struktur sowohl eine A halten C und einem B:

C.A = struct A; 
C.B = struct B; 

mit Zugang dann so etwas wie

C.A.field1; 
C.A.field2; 
C.B.field3; 
C.B.field4; 

hoffe, das hilft!

EDIT: beide Lösungen vermeiden Namenskollisionen.

Außerdem habe ich Ihre matlab Tag nicht gesehen. Per Konvention sollten Sie die Frage so bearbeiten, dass sie diese Information enthält.

4

Ich denke nicht, dass Sie Konflikte gut ohne Schleife bewältigen können, noch glaube ich, dass Sie eine vermeiden müssen. (obwohl ich denke, Effizienz könnte ein Problem mit vielen vielen Feldern sein ...)

Ich benutze eine Funktion, die ich vor ein paar Jahren schrieb setdefaults.m, die eine Struktur mit den Werten einer anderen Struktur kombiniert, wo man Vorrang hat über den anderen im Falle eines Konflikts.

% SETDEFAULTS sets the default structure values 
% SOUT = SETDEFAULTS(S, SDEF) reproduces in S 
% all the structure fields, and their values, that exist in 
% SDEF that do not exist in S. 
% SOUT = SETDEFAULTS(S, SDEF, OVERRIDE) does 
% the same function as above, but if OVERRIDE is 1, 
% it copies all fields of SDEF to SOUT. 

function sout = setdefaults(s,sdef,override) 
if (not(exist('override','var'))) 
    override = 0; 
end 

sout = s; 
for f = fieldnames(sdef)' 
    cf = char(f); 
    if (override | not(isfield(sout,cf))) 
     sout = setfield(sout,cf,getfield(sdef,cf)); 
    end 
end 

Jetzt, wo ich darüber nachdenke, bin ich ziemlich sicher, dass die „überschreiben“ Eingabe nicht erforderlich ist (man kann nur die Reihenfolge der Eingänge wechseln), obwohl ich das nicht 100% sicher bin .. ., so ist hier eine einfachere Rewrite (setdefaults2.m):

% SETDEFAULTS2 sets the default structure values 
% SOUT = SETDEFAULTS(S, SDEF) reproduces in S 
% all the structure fields, and their values, that exist in 
% SDEF that do not exist in S. 

function sout = setdefaults2(s,sdef) 
sout = sdef; 
for f = fieldnames(s)' 
    sout = setfield(sout,f{1},getfield(s,f{1})); 
end 

und einige Proben zu testen:

>> S1 = struct('a',1,'b',2,'c',3); 
>> S2 = struct('b',4,'c',5,'d',6); 
>> setdefaults2(S1,S2) 

ans = 

    b: 2 
    c: 3 
    d: 6 
    a: 1 

>> setdefaults2(S2,S1) 

ans = 

    a: 1 
    b: 4 
    c: 5 
    d: 6 
+0

Danke, das ist genau das Verhalten, das ich brauche. Ich frage mich, warum es kein Teil der Standardbibliothek ist. –

+0

Ab MATLAB 6.5 (Release 13) können dynamische Feldreferenzen verwendet werden, um die Anweisung innerhalb der Schleife zu vereinfachen: 'sout. (F {1}) = s. (F {1});' –

5

ich ein schönes solution on File Exchange: catstruct gefunden haben.

Ohne die Leistung zu testen, kann ich sagen, dass es genau das getan hat, was ich wollte. Es kann natürlich mit doppelten Feldern umgehen.

Hier ist, wie es funktioniert:

a.f1 = 1; 
a.f2 = 2; 
b.f2 = 3; 
b.f4 = 4; 

s = catstruct(a,b) 

s = 

    f1: 1 
    f2: 3 
    f3: 4 
8

Kurze Antwort geben: setstructfields (wenn Sie das Signal Processing Toolbox).


Die offizielle Lösung wird von Loren Shure auf her MathWorks blog veröffentlicht und von SCFrench here und in Eitan T's answer to a different question demonstriert. Wenn Sie jedoch die Signal Processing Toolbox haben, tut dies eine einfache undokumentierte Funktion - setstructfields.

help setstructfields

setstructfields Set fields of a structure using another structure 
    setstructfields(STRUCTIN, NEWFIELDS) Set fields of STRUCTIN using 
    another structure NEWFIELDS fields. If fields exist in STRUCTIN 
    but not in NEWFIELDS, they will not be changed. 

verwendet intern es fieldnames und eine for Schleife, so dass es eine Komfortfunktion mit Fehlerprüfung und die Rekursion für Felder, die sie structs sind.

Beispiel

der "Original" struct:

% struct with fields 'color' and 'count' 
s = struct('color','orange','count',2) 

s = 
    color: 'orange' 
    count: 2 

Ein zweiter struct einen neuen Wert für 'count', und ein neues Feld, 'shape' enthält:

% struct with fields 'count' and 'shape' 
s2 = struct('count',4,'shape','round') 

s2 = 
    count: 4 
    shape: 'round' 

Aufruf setstructfields :

>> s = setstructfields(s,s2) 
s = 
    color: 'orange' 
    count: 4 
    shape: 'round' 

Das Feld 'count' ist aktualisiert. Das Feld 'shape' ist hinzugefügt. Das Feld 'color'bleibt unverändert.

HINWEIS: Da die Funktion nicht dokumentiert ist, kann sie sich jederzeit ändern oder entfernt werden.

Verwandte Themen