Я хочу объединить две структуры с разными именами полей.
Например, начиная с:
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.





В C структура может иметь другую структуру в качестве одного из членов. Хотя это не совсем то же самое, что вы спрашиваете, вы можете получить либо ситуацию, когда одна структура содержит другую, либо одна структура содержит две структуры, каждая из которых содержит части информации, которую вы хотели.
псевдокод: я не помню фактический синтаксис.
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. По соглашению вы должны захотеть отредактировать вопрос, включив в него эту информацию.
Без столкновений можно обойтись
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 для постепенного перехода к случаю обработки конфликта.
Я не думаю, что вы можете хорошо справляться с конфликтами без цикла, и не думаю, что вам нужно его избегать. (хотя я полагаю, что эффективность может быть проблемой во многих областях ...)
Я использую функцию 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
Спасибо, это именно то поведение, которое мне нужно. Интересно, почему он не входит в стандартную библиотеку.
Начиная с MATLAB 6.5 (Release 13), динамические ссылки на поля могут использоваться для упрощения оператора внутри цикла: sout.(f{1}) = s.(f{1});
Я нашел хороший решение для обмена файлами: catstruct.
Не проверяя производительность, могу сказать, что он сделал именно то, что я хотел. Конечно, он может работать с повторяющимися полями.
Вот как это работает:
a.f1 = 1;
a.f2 = 2;
b.f2 = 3;
b.f4 = 4;
s = catstruct(a,b)
Дам
s =
f1: 1
f2: 3
f3: 4
Краткий ответ: setstructfields (если у вас есть Signal Processing Toolbox).
Официальное решение опубликовано Лореном Шуре на ее блог 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'остается неизменной.
ПРИМЕЧАНИЕ: Поскольку функция недокументирована, она может быть изменена или удалена в любое время.
Первое решение могло быть преобразовано в однострочник с помощью
cell2struct. Хотя я не знаю, как это работает.