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

matlab merge structure field

17753 просмотра

5 ответа

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

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

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?

РЕДАКТИРОВАТЬ: Давайте предположим, что в случае конфликтов имен полей мы отдаем предпочтение A.

Автор: KennyMorton Источник Размещён: 29.07.2019 03:53

Ответы (5)


18 плюса

Решение

Без столкновений можно обойтись

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изящного перехода к случаю обработки конфликта.

Автор: SCFrench Размещён: 02.09.2008 02:36

8 плюса

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


Официальное решение опубликовано Лорен Шуре в ее блоге на MathWorks и продемонстрировано SCFrench здесь и в ответе Эйтана Т на другой вопрос . Однако, если у вас есть набор инструментов для обработки сигналов, простая недокументированная функция уже делает это - 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' остается без изменений .

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

Автор: chappjc Размещён: 20.05.2014 06:45

5 плюса

Я нашел хорошее решение для обмена файлами: catstruct .

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

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

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

s = catstruct(a,b)

Дам

s = 

    f1: 1
    f2: 3
    f3: 4
Автор: Dennis Jaheruddin Размещён: 19.09.2013 11:45

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

Теперь, когда я думаю об этом, я почти уверен, что ввод «переопределить» не нужен (вы можете просто изменить порядок входов), хотя я не уверен на 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
Автор: Jason S Размещён: 10.12.2008 07:58

2 плюса

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

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

РЕДАКТИРОВАТЬ: оба эти решения позволяют избежать коллизии имен.

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

Автор: pbh101 Размещён: 02.09.2008 12:43
Вопросы из категории :
32x32