Как фильтровать данные из массива struct, когда определенные поля пусты

#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; ... .