Подтвердить что ты не робот

Каковы некоторые эффективные способы объединения двух структур в MATLAB?

Я хочу объединить две структуры с разными именами полей.

Например, начиная с:

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

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

Я бы хотел:

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

Есть ли более эффективный способ, чем использование "fieldnames" и цикла for?

EDIT: Предположим, что в случае конфликтов имен полей мы отдаем предпочтение A.

4b9b3361

Ответ 1

Без коллизий вы можете сделать

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

И это разумно эффективно. Однако ошибки struct в повторяющихся именах полей и предварительная проверка их с помощью unique убивают производительность до такой степени, что цикл лучше. Но вот как это будет выглядеть:

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

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

C=struct(M{:});

Возможно, вы сможете создать гибридное решение, не допуская конфликтов и используя try/catch вокруг вызова struct, чтобы грамотно деградировать в случае обработки конфликта.

Ответ 2

Короткий ответ: setstructfields (если у вас есть панель инструментов обработки сигналов).


Официальное решение опубликовано Loren Shure на ее блог MathWorks и продемонстрировано SCFrench здесь и в Eitan T ответит на другой вопрос. Однако, если у вас есть Toolbox Toolbox, простая недокументированная функция делает это уже - 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.

Внутри он использует цикл fieldnames и for, поэтому это удобная функция с проверкой ошибок и рекурсией для полей, которые сами являются структурами.

Пример

"Оригинальная" структура:

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

s = 
    color: 'orange'
    count: 2

Вторая структура, содержащая новое значение для 'count', и новое поле 'shape':

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

s2 = 
    count: 4
    shape: 'round'

Вызов setstructfields:

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

Обновлено поле 'count'. Добавлено поле 'shape'. Поле 'color' остается неизменным.

ПРИМЕЧАНИЕ. Поскольку функция недокументирована, она может быть изменена или удалена в любое время.

Ответ 3

Я нашел хорошее решение на File Exchange: catstruct.

Без тестирования производительности я могу сказать, что он сделал именно то, что я хотел. Конечно, он может иметь дело с повторяющимися полями.

Вот как это работает:

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

s = catstruct(a,b)

Дает

s = 

    f1: 1
    f2: 3
    f3: 4

Ответ 4

Я не думаю, что вы можете справляться с конфликтами хорошо, без цикла, и я не думаю, что вам нужно его избегать. (хотя я полагаю, что эффективность может быть проблемой с множеством полей...)

Я использую функцию, которую я написал несколько лет назад под названием setdefaults.m, которая объединяет одну структуру со значениями другой структуры, где в случае конфликта имеет приоритет над другим.

% 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

Теперь, когда я думаю об этом, я уверен, что вход "override" не нужен (вы можете просто переключить порядок входов), хотя я не уверен на 100%... поэтому здесь проще переписать (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

и некоторые образцы для проверки:

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

Ответ 5

В C структура может иметь другую структуру как один из ее членов. Хотя это не совсем то же самое, что и вы спрашиваете, вы можете столкнуться либо с ситуацией, когда одна структура содержит другую, либо одна структура содержит две структуры, каждая из которых содержит части информации, которые вы хотели.

psuedocode: я не помню фактический синтаксис.

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

для доступа:   A.field3.field4;

или что-то в этом роде.

Или вы могли бы иметь структуру C удерживать как A, так и B:

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

с доступом, то что-то вроде

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

надеюсь, что это поможет!

EDIT: оба этих решения избегают коллизий имен.

Кроме того, я не видел тэга matlab. По соглашению, вы должны отредактировать вопрос, чтобы включить эту часть информации.