Pergunta

Eu quero combinar duas estruturas com diferentes nomes de campos.

Por exemplo, começando com:

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

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

Eu gostaria de ter:

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

Há uma forma mais eficiente que o uso de "campos" e para um ciclo?

EDITAR: Vamos supor que, no caso do campo de conflitos de nome damos preferência para A.

Foi útil?

Solução

Sem colisões, você pode fazer

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

E este é razoavelmente eficiente.No entanto, struct erros em duplicado fieldnames, e pré-verificando-los usando unique mata de desempenho, a ponto de que um ciclo é o melhor.Mas aqui está o que seria parecido com:

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

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

C=struct(M{:});

Você pode ser capaz de fazer de uma solução híbrida, assumindo, sem conflitos e usando um try/catch em torno da chamada para struct para degradar naturalmente para o tratamento de conflitos de caso.

Outras dicas

Resposta curta: setstructfields (se você tiver o Processamento de Sinal de Ferramentas).


A solução oficial postado por Loren Shure em ela MathWorks blog, e demonstrado por SCFrench aqui e no Eitan T para responder a uma pergunta diferente.No entanto, se você tiver o Processamento de Sinal de Ferramentas, uma simples função não documentada isso já 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 ele usa fieldnames e um for loop, portanto, é uma função de conveniência com a verificação de erros e a recursividade para campos que são próprias estruturas.

Exemplo

O "original" struct:

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

s = 
    color: 'orange'
    count: 2

Uma segunda estrutura que contém um novo valor para 'count', e um novo campo, 'shape':

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

s2 = 
    count: 4
    shape: 'round'

Chamar setstructfields:

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

O campo 'count' é atualizado.O campo 'shape' é adicionado.O campo 'color' permanece inalterado.

NOTA:Uma vez que a função é não documentado, ele pode mudar ou ser removido a qualquer momento.

Eu encontrei um bom solução de Arquivo do Exchange:catstruct.

Sem testar o desempenho, posso dizer que ele fez exatamente o que eu queria.Ele pode lidar com campos duplicados do curso.

Aqui está como funciona:

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

s = catstruct(a,b)

Vai dar

s = 

    f1: 1
    f2: 3
    f3: 4

Eu não acho que você pode lidar com conflitos bem w/s de um ciclo, mas não acho que você precisa evitar.(embora eu suponha que a eficiência pode ser um problema w/ muitos campos...)

Eu uso uma função escrevi alguns anos atrás chamado setdefaults.m, que combina uma estrutura com os valores de uma outra estrutura, onde um tem precedência sobre as outras, em caso de conflito.

% 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

Agora que eu penso sobre isso, eu tenho certeza de que a "substituição" de entrada é desnecessário (você pode apenas mudar a ordem das entradas) que eu não tenho 100% de certeza de que...então, aqui está a mais simples 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

e algumas amostras para o teste:

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

Em C, uma estrutura pode ter outra estrutura, como um de seus membros.Enquanto isso não é exatamente o mesmo como o que você está pedindo, você pode acabar com uma situação em que uma estrutura contém outro, ou uma estrutura que contém duas estruturas, tanto dos que possuem peças de informação que você queria.

psuedocode:eu não me lembro a sintaxe real.

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

para acessar:A. campo3.campo4;

ou algo do tipo.

Ou você poderia ter struct C mantenha um A e um B:

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

com o acesso, em seguida, algo como

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

espero que isso ajude!

EDITAR:ambas as soluções evitar conflitos de nomes.

Também, eu não vejo o seu matlab etiqueta.Por convenção, você deve querer editar a pergunta para incluir esse pedaço de informação.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top