Domanda

Voglio combinare due strutture con nomi di campi diversi.

Ad esempio, iniziando con:

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?

MODIFICARE: Supponiamo che in caso di conflitti di nomi di campo diamo la preferenza a A.

È stato utile?

Soluzione

Senza collisioni, puoi farlo

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

E questo è ragionevolmente efficiente.Tuttavia, struct errori sui nomi di campo duplicati e controllo preliminare utilizzandoli unique uccide le prestazioni 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 presupponendo che non vi siano conflitti e utilizzando un try/catch attorno alla chiamata a struct degradare con garbo al caso di gestione del conflitto.

Altri suggerimenti

Risposta breve: setstructfields (se disponi del Signal Processing Toolbox).


La soluzione ufficiale è pubblicata da Loren Shure su il suo blog MathWorks, e dimostrato da SCFrancese qui e dentro La risposta di Eitan T a una domanda diversa.Tuttavia, se disponi del 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 for loop, quindi è una funzione comoda 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' È aggiornato.Il campo 'shape' È aggiunto.Il campo 'color' Rimane invariato.

NOTA:Poiché la funzione non è documentata, potrebbe cambiare o essere rimossa in qualsiasi momento.

Ho trovato un bel soluzione su Scambio file:catstruct.

Senza testare le prestazioni posso dire che ha fatto esattamente quello che volevo.Naturalmente può gestire campi duplicati.

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 senza un ciclo, né penso che dovresti evitarne uno.(anche se suppongo che l'efficienza potrebbe essere un problema in molti campi...)

Utilizzo una funzione che ho scritto qualche anno fa chiamata setdefaults.m, che combina una struttura con i valori di un'altra struttura, dove l'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 sia 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 struttura può avere un'altra struttura come uno dei suoi membri.Sebbene questo non sia esattamente lo stesso di quello che stai chiedendo, potresti ritrovarti con una situazione in cui una struttura ne contiene un'altra o una struttura contiene due strutture, entrambe contenenti parti delle informazioni che volevi.

pseudocodice:non ricordo la sintassi effettiva.

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

accedere:A.campo3.campo4;

o qualcosa del genere.

Oppure potresti avere la struttura C che contiene sia A che B:

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

con accesso quindi qualcosa del genere

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

spero che questo ti aiuti!

MODIFICARE:entrambe queste soluzioni evitano di nominare le collisioni.

Inoltre non ho visto il tuo matlab etichetta.Per convenzione, dovresti modificare la domanda per includere quell'informazione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top