#matlab
#matlab
Вопрос:
У меня есть массив struct с определенными полями. Теперь я хочу отфильтровать все строки, в которых определенные поля пусты.
В основном то, что у меня сейчас есть:
data(1).elem1 = 1;
data(1).elem2 = 2;
data(1).elem3 = 3;
data(2).elem1 = 4;
data(2).elem3 = 6;
data(3).elem1 = 7;
data(3).elem2 = 8;
data(4).elem1 = 9;
data(4).elem2 = 10;
data(4).elem3 = 11;
data(5).elem1 = 9;
data(5).elem3 = 11;
data
fields = {'elem2,elem3'};
data(any(~cellfun(@(x) any(~isempty(x)), {data.('elem2'); data.('elem3')}))) = [];
Это работает нормально. Однако я не хочу выражать {data.('elem2'); data.('elem3')}
конкретно. Я хочу просто использовать переменную fields
.
Я могу перебирать поля и создавать временную переменную, которая содержит {data.('elem2'); data.('elem3')}
. Однако я предпочитаю этого не делать. Потому что я думаю, что есть более умный способ, и мне интересно, нельзя ли это сделать более эффективно, как я делаю в настоящее время.
Комментарии:
1. У вас ошибка в определении
fields
. Так и должно бытьfields = {'elem2', 'elem3'};
. Затем вы можете написатьdata(any(cellfun(@(x) isempty(x), {data.(fields{1});data.(fields{2})}))) = [];
(у вас есть одно дополнительноеany
и 2 дополнительных отрицания!)
Ответ №1:
Вы можете преобразовать структуру в ячейку и использовать cellfun
для проверки наличия пустых значений для любого поля. Затем используйте ismember
, чтобы найти индекс полей для проверки.
fields = {'elem2','elem3'};
emptyIdx = squeeze(cellfun('isempty', struct2cell(data)));
idxToRemove = any(emptyIdx(ismember(fieldnames(data), fields),:), 1);
Пример:
data(1).elem1 = 1;
data(1).elem2 = 2;
data(1).elem3 = 3;
data(2).elem1 = 4;
data(2).elem3 = 6;
data(3).elem1 = 7;
data(3).elem2 = 8;
data(4).elem1 = 2;
data(4).elem3 = 5;
data(4).elem2 = 4;
Предоставляет структуру данных только с индексом 1 и 4
data =
1x2 struct array with fields:
elem1
elem2
elem3
Комментарии:
1. Хотя я думаю, что могу использовать части кода, код работает не так, как я хочу, попробуйте протестировать его с помощью примера набора данных. Он не удаляет никаких элементов.
2. Код фактически фильтрует по полям, а не по элементам
data
. Попробуйте свой код с моим добавленным набором данных. Причина, по которой это сработало, заключалась в том, что количество элементов было равно количеству полей.3. @WG- True, смешанная строка и столбец. Обновил мое решение, используя
squeeze
Ответ №2:
Вот один из способов сделать это
I=ismember(fieldnames(data), {'elem2', 'elem3'});
data(~arrayfun(@(x) any(I amp; structfun(@isempty, x)), data))=[];
Найдите индексы интересующих полей. Перебираем все элементы data
using arrayfun
, а затем перебираем все поля using structfun
и игнорируем поля, которые нас не интересуют I amp; ...
.