Quali sono alcuni modi efficaci per combinare due strutture in MATLAB?

Voglio combinare due strutture con nomi di campi diversi.

Ad esempio, a partire da:

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

Vorrei avere:

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

Esiste un modo più efficiente rispetto all’utilizzo di “fieldnames” e un ciclo for?

EDIT: Supponiamo che nel caso dei conflitti dei nomi dei campi diamo la preferenza ad A

Senza collisioni, puoi farlo

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

E questo è ragionevolmente efficiente. Tuttavia, gli errori di struct sui nomi di campi duplicati e il controllo preliminare per essi utilizzano prestazioni di uccisioni unique al punto che un loop è migliore. Ma ecco come sarebbe:

 M = [fieldnames(A)' fieldnames(B)'; struct2cell(A)' struct2cell(B)']; [tmp, rows] = unique(M(1,:), 'last'); M=M(:, rows); C=struct(M{:}); 

Potresti essere in grado di creare una soluzione ibrida non assumendo conflitti e utilizzando un try / catch attorno alla chiamata di struct per degradare con grazia al caso di gestione dei conflitti.

Risposta breve: setstructfields (se avete il Signal Processing Toolbox).


La soluzione ufficiale è stata pubblicata da Loren Shure sul suo blog MathWorks e dimostrata da SCFrench qui e nella risposta di Eitan T a una domanda diversa . Tuttavia, se hai il Signal Processing Toolbox, una semplice funzione non documentata lo fa già – 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. 

Internamente utilizza fieldnames e un ciclo for , quindi è una funzione di convenienza con controllo degli errori e ricorsione per i campi che sono essi stessi strutture.

Esempio

La struttura “originale”:

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

Una seconda struttura contenente un nuovo valore per 'count' e un nuovo campo, 'shape' :

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

Chiamando setstructfields :

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

Il campo 'count' viene aggiornato . Il campo 'shape' è aggiunto . Il campo 'color' rimane invariato .

NOTA : poiché la funzione non è documentata, può essere modificata o rimossa in qualsiasi momento.

Ho trovato una bella soluzione su File Exchange: catstruct .

Senza testare la performance, posso dire che ha fatto esattamente quello che volevo. Può trattare con campi duplicati, ovviamente.

Ecco come funziona:

 a.f1 = 1; a.f2 = 2; b.f2 = 3; b.f4 = 4; s = catstruct(a,b) 

Darà

 s = f1: 1 f2: 3 f3: 4 

Non penso che tu possa gestire bene i conflitti con il ciclo, né penso che tu debba evitarlo. (anche se suppongo che l’efficienza potrebbe essere un problema con molti campi …)

Uso una funzione che ho scritto qualche anno fa chiamata setdefaults.m , che combina una struttura con i valori di un’altra struttura, in cui uno ha la precedenza sull’altro in caso di conflitto.

 % 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 

Ora che ci penso, sono abbastanza sicuro che l’input “override” non è necessario (puoi semplicemente cambiare l’ordine degli input) anche se non ne sono sicuro al 100% … quindi ecco una riscrittura più semplice ( 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 

e alcuni campioni per testarlo:

 >> 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 

In C, una struct può avere un’altra struct come uno dei suoi membri. Anche se questo non è esattamente lo stesso di quello che stai chiedendo, potresti finire con una situazione in cui una struttura ne contiene un’altra, o una struttura contiene due strutture, entrambe le quali contengono parti delle informazioni che volevi.

psuedocode: non ricordo la syntax attuale.

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

accedere a: A.field3.field4;

o qualcosa del genere.

Oppure potresti avere struct C in attesa sia di A che di B:

 CA = struct A; CB = struct B; 

con accesso quindi qualcosa di simile

 CAfield1; CAfield2; CBfield3; CBfield4; 

spero che questo ti aiuti!

EDIT: entrambe queste soluzioni evitano di nominare collisioni.

Inoltre, non ho visto il tuo tag matlab . Per convenzione, dovresti modificare la domanda per includere quella parte di informazioni.