Quels sont certains des moyens efficaces pour combiner les deux structures dans MATLAB?

StackOverflow https://stackoverflow.com/questions/38645

  •  09-06-2019
  •  | 
  •  

Question

Je veux combiner les deux structures avec différents noms de champs.

Par exemple, en commençant par:

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

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

Je voudrais avoir:

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

Est-il un moyen plus efficace que l'utilisation de "fieldnames" et d'une boucle for?

EDIT: Supposons que, dans le cas d'un champ de conflits de nom de nous donner la préférence à A.

Était-ce utile?

La solution

Sans collisions, vous pouvez le faire

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

Et cela est relativement efficace.Cependant, struct les erreurs sur un double fieldnames, et la pré-vérification à l'aide de unique tue les performances au point qu'une boucle est mieux.Mais voici à quoi il pourrait ressembler:

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

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

C=struct(M{:});

Vous pourriez être en mesure d'apporter une solution hybride en supposant l'absence de conflits et à l'aide d'un try/catch autour de l'appel à struct normalement dégradent à la gestion des conflits de cas.

Autres conseils

Réponse courte: setstructfields (si vous avez la boîte à outils de Traitement du Signal).


La solution officielle est posté par Loren Shure sur son MathWorks blog, et démontré par SCFrench ici et dans Eitan T de la réponse à une autre question.Toutefois, si vous avez la boîte à outils de Traitement du Signal, une simple sans-papiers, la fonction n'est ce dé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.

En interne, il utilise fieldnames et un for boucle, donc c'est une fonction de commodité avec la vérification des erreurs et de la récursivité pour les champs qui sont eux-mêmes des structures.

Exemple

L ' "original" struct:

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

s = 
    color: 'orange'
    count: 2

Une deuxième structure contenant une nouvelle valeur pour 'count', et un nouveau champ, 'shape':

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

s2 = 
    count: 4
    shape: 'round'

L'appel setstructfields:

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

Le domaine 'count' est mise à jour.Le domaine 'shape' est ajouté.Le domaine 'color' reste inchangé.

NOTE:Étant donné que la fonction sans-papiers, il peut changer ou être retiré à tout moment.

J'ai trouvé une belle solution d'Échange de Fichiers:catstruct.

Sans tester les performances, je peux dire qu'il a fait exactement ce que je voulais.Il peut traiter avec des champs en double bien sûr.

Voici comment il fonctionne:

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

s = catstruct(a,b)

Donnera

s = 

    f1: 1
    f2: 3
    f3: 4

Je ne pense pas que vous pouvez gérer les conflits bien w/o d'une boucle, je ne pense que vous auriez besoin d'en éviter un.(bien que je suppose que l'efficacité pourrait être un problème w/ beaucoup de beaucoup de champs...)

J'utilise une fonction que j'ai écrit quelques années en arrière, appelé setdefaults.m, qui combine une structure avec les valeurs d'une autre structure, où l'on prend le dessus sur l'autre en cas de conflit.

% 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

Maintenant que j'y pense, je suis assez sûr que le "remplacement" d'entrée est inutile (il vous suffit de changer l'ordre des entrées) si je ne suis pas sûr à 100% de ce que...voici donc une simple réécriture (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

et quelques échantillons à tester:

>> 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, une structure peut avoir une autre structure comme l'un de ses membres.Alors que ce n'est pas exactement la même que ce que vous demandez, vous pourriez vous retrouver avec une situation où l'on struct contient une autre, ou un struct contient deux structures, qui contiennent des parties de l'info que tu voulais.

psuedocode:je ne me souviens pas le réel de la syntaxe.

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

pour y accéder:A. champ3.field4;

ou quelque chose du genre.

Ou vous pourriez avoir struct C titulaire à la fois d'un A et un B:

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

avec l'accès à quelque chose comme

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

espérons que cette aide!

EDIT:ces deux solutions éviter les conflits de noms.

Aussi, je n'ai pas vu votre matlab la balise.Par convention, on souhaite modifier la question pour inclure ce morceau de l'info.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top