Как получить доступ к полям структуры динамически?

31

У меня есть структура со многими полями, которые являются векторами разной длины. Я хотел бы получить доступ к полям внутри цикла, по порядку. Я попробовал getfield следующим образом, но MATLAB это не нравится. Как я могу это сделать?

S = struct('A', [1 2], 'B',[3 4 5]);
SNames = fieldnames(S);
for loopIndex = 1:2
  field = getfield(S, SNames(loopIndex));
  %do stuff w/ field
end
??? Index exceeds matrix dimensions

Я использую структуры в первую очередь потому, что у массива возникнут проблемы с разными полями. Есть ли лучшая альтернатива этому?

Теги:
matlab-struct

6 ответов

43
Лучший ответ

Попробуйте ссылку на динамическое поле, где вы помещаете строку в круглую скобку, как показано на строке, определяющей материал.

S = struct('A', [1 2], 'B',[3 4 5]); 
SNames = fieldnames(S); 
for loopIndex = 1:numel(SNames) 
    stuff = S.(SNames{loopIndex})
end 

Я согласен со Стивом и Адамом. Используйте ячейки. Этот синтаксис подходит для людей в других ситуациях, хотя!

15

Есть три момента, которые я хотел бы сделать здесь:

  • Причина, по которой вы получаете ошибку в своем предыдущем коде, связана с тем, как вы индексируете SNames. Функция fieldnames возвращает массив ячеек строки, поэтому вам нужно использовать индексацию содержимого (то есть фигурные скобки) для доступа к строковым значениям. Если вы измените четвертую строку в своем коде на это:

    field = getfield(S, SNames{loopIndex});
    

    тогда ваш код должен работать без ошибок.

  • Как предложено MatlabDoug, вы можете использовать имена динамических полей, чтобы избежать использования getfield (что, на мой взгляд, дает более чистый код).

  • Предложение от Adam вместо

  • 0
    Однако использование массива ячеек вместо структуры менее многословно.
4

Подход Getfield подходит (хотя у меня нет MATLAB, доступного прямо сейчас, и мне не ясно, почему выше не работает).

Для альтернативной структуры данных вы также можете посмотреть в массивы ячеек MATLAB. Они также позволят вам хранить и индексировать векторы различной длины.

  • 1
    Учитывая ваше описание того, почему вы используете структуру, я согласен с Адамом. Вы должны рассмотреть возможность использования массива ячеек вместо этого.
3

Вы можете использовать двоеточие, чтобы избежать индексов:

S = struct('A', [1 2], 'B',[3 4 5]); 
SNames = fieldnames(S); 
for SName = [SNames{:}]
    stuff = S.(SName)
end
  • 0
    ПРИМЕЧАНИЕ. Это работает только потому, что имена полей имеют одну букву. Это не работает в целом.
2

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

S = struct('A', [1 2], 'B',[3 4 5]); 
S_Cell = struct2cell(S);
%Then as per gnovice
for loopIndex = 1:numel(S_Sell)   % Loop over the number of cells
    array = S{loopIndex};         % Access the contents of each cell
    %# Do stuff with array
end

Я использовал что-то подобное для того, что было сгенерировано в структуре, и тогда мне нужно было получить к нему доступ как матрицу, в этом случае это было так просто, как

M = cell2mat(struct2cell(S));

Чтобы преобразовать его в матрицу

  • 0
    М = table2array (struct2table (S));
0

Просто добавьте еще один ответ на микс. Мне нравится решение от @Niver, но оно работает только для полей с однобуквенными именами. Решение, которое я использовал, было:

S = struct('A', [1 2], 'B',[3 4 5], 'Cee', [6 7]); 
for SName = fieldnames(S)'
    stuff = S.(SName{1})
end

for будет проходить через столбцы массива ячеек (следовательно, транспонировать на fieldnames(S)'). Для каждого цикла SName становится массивом ячеек 1x1, поэтому мы используем индексацию содержимого для доступа к первому и единственному элементу с SName{1}.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню