Pregunta

Quiero combinar dos estructuras con nombres de campos diferentes.

Por ejemplo, comenzando con:

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

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

Me gustaría tener:

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

¿Existe una forma más eficiente que usar "nombres de campo" y un bucle for?

EDITAR: Supongamos que en el caso de conflictos de nombres de campos damos preferencia a A.

¿Fue útil?

Solución

Sin colisiones, puedes hacerlo.

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

Y esto es razonablemente eficiente.Sin embargo, struct errores en nombres de campos duplicados y verificarlos previamente usando unique mata el rendimiento hasta el punto de que un bucle es mejor.Pero así es como se vería:

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

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

C=struct(M{:});

Es posible que pueda crear una solución híbrida asumiendo que no hay conflictos y utilizando un intento/captura de la llamada para struct para degradarse con gracia al caso de manejo de conflictos.

Otros consejos

Respuesta corta: setstructfields (si tiene la Caja de herramientas de procesamiento de señales).


La solución oficial fue publicada por Loren Shure en su blog de MathWorks, y demostrado por SCfrancés aquí y en La respuesta de Eitan T a una pregunta diferente.Sin embargo, si tiene la Caja de herramientas de procesamiento de señales, una función simple no documentada ya hace esto: 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 utiliza fieldnames y un for bucle, por lo que es una función conveniente con verificación de errores y recursividad para campos que son en sí mismos estructuras.

Ejemplo

La estructura "original":

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

s = 
    color: 'orange'
    count: 2

Una segunda estructura que contiene un nuevo valor para 'count', y un nuevo campo, 'shape':

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

s2 = 
    count: 4
    shape: 'round'

Vocación setstructfields:

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

El campo 'count' es actualizado.El campo 'shape' es agregado.El campo 'color' permanece sin cambios.

NOTA:Dado que la función no está documentada, puede cambiar o eliminarse en cualquier momento.

he encontrado un bonito solución en intercambio de archivos:estructura de gato.

Sin probar el rendimiento puedo decir que hizo exactamente lo que quería.Por supuesto, puede manejar campos duplicados.

Así es como funciona:

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

s = catstruct(a,b)

Daré

s = 

    f1: 1
    f2: 3
    f3: 4

No creo que puedas manejar bien los conflictos sin un bucle, ni creo que debas evitar uno.(aunque supongo que la eficiencia podría ser un problema en muchos campos...)

Utilizo una función que escribí hace unos años llamada setdefaults.m, que combina una estructura con los valores de otra estructura, donde uno tiene prioridad sobre el otro en caso de conflicto.

% 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

Ahora que lo pienso, estoy bastante seguro de que la entrada "anular" es innecesaria (simplemente puedes cambiar el orden de las entradas), aunque no estoy 100% seguro de eso...así que aquí hay una reescritura más simple (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

y algunas muestras para probarlo:

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

En C, una estructura puede tener otra estructura como uno de sus miembros.Si bien esto no es exactamente lo mismo que estás preguntando, podrías terminar con una situación en la que una estructura contiene otra, o una estructura contiene dos estructuras, las cuales contienen partes de la información que deseas.

pseudocódigo:No recuerdo la sintaxis real.

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

acceder:A.campo3.campo4;

O algo por el estilo.

O podría hacer que la estructura C contenga tanto una A como una B:

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

con acceso entonces algo como

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

¡espero que esto ayude!

EDITAR:Ambas soluciones evitan colisiones de nombres.

Además, no vi tu matlab etiqueta.Por convención, deberías editar la pregunta para incluir esa información.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top