Как мне перебрать каждый элемент в n-мерной матрице в MATLAB?

У меня проблема. Мне нужно перебрать каждый элемент в n-мерной матрице в MATLAB. Проблема в том, что я не знаю, как это сделать для произвольного числа измерений. Я знаю, что могу сказать

for i = 1:size(m,1)
    for j = 1:size(m,2)
        for k = 1:size(m,3)

и так далее, но есть ли способ сделать это для произвольного числа измерений?

вопрос задан 17.04.2009
rlbond
37768 репутация

8 ответов


  • 83 рейтинг

    Вы можете использовать линейное индексирование для доступа к каждому элементу.

    for idx = 1:numel(array)
        element = array(idx)
        ....
    end
    

    Это полезно, если вам не нужно знать, чем вы занимаетесь. Однако, если вам не нужно знать, по какому индексу вы находитесь, вам, вероятно, лучше использовать arrayfun ()

    ответ дан Andrew, с репутацией 1067, 17.04.2009
  • 33 рейтинг

    Идея линейного индекса для массивов в Matlab является важной. Массив в MATLAB - это просто вектор элементов, расположенных в памяти. MATLAB позволяет использовать либо индекс строки и столбца, либо один линейный индекс. Например,

    A = magic(3)
    A =
         8     1     6
         3     5     7
         4     9     2
    
    A(2,3)
    ans =
         7
    
    A(8)
    ans =
         7
    

    Мы можем видеть порядок хранения элементов в памяти, развернув массив в вектор.

    A(:)
    ans =
         8
         3
         4
         1
         5
         9
         6
         7
         2
    

    Как видите, 8-й элемент - это номер 7. Фактически функция find возвращает свои результаты в виде линейного индекса.

    find(A>6)
    ans =
         1
         6
         8
    

    В результате мы можем получить доступ к каждому элементу по очереди из общего массива n-d, используя один цикл. Например, если мы хотим возвести в квадрат элементы A (да, я знаю, что есть лучшие способы сделать это), можно сделать это:

    B = zeros(size(A));
    for i = 1:numel(A)
      B(i) = A(i).^2;
    end
    
    B
    B =
        64     1    36
         9    25    49
        16    81     4
    

    Есть много обстоятельств, когда линейный индекс более полезен. Преобразование между линейным индексом и двух (или более) размерными индексами выполняется с помощью функций sub2ind и ind2sub.

    Линейный индекс применяется в целом к ​​любому массиву в Matlab. Таким образом, вы можете использовать его для структур, клеточных массивов и т. Д. Единственная проблема с линейным индексом - когда они становятся слишком большими. MATLAB использует 32-битное целое число для хранения этих индексов. Таким образом, если в вашем массиве более 2 ^ 32 элементов, линейный индекс потерпит неудачу. Это действительно только проблема, если вы часто используете разреженные матрицы, а иногда это вызывает проблемы. (Хотя я не использую 64-битную версию MATLAB, я считаю, что проблема была решена для тех счастливчиков, которые ее используют. )

    ответ дан does_not_exist, с репутацией , 17.04.2009
  • 15 рейтинг

    Как указано в нескольких других ответах, вы можете перебирать все элементы в матрице A (любого измерения), используя линейный индекс от 1 до цифр (A) в одном цикле for. Вы можете использовать несколько других приемов: ARRAYFUN и CELLFUN .

    Давайте сначала предположим, что у вас есть функция, которую вы хотите применить к каждому элементу A (называемый «my_func»). Сначала вы создаете описатель функции для этой функции:

    fcn = @my_func;
    

    Если A - это матрица (типа double, single и т. Д. ) произвольного измерения, вы можете использовать ARRAYFUN, чтобы применить «my_func» к каждому элементу:

    outArgs = arrayfun(fcn,A);
    

    Если A - это массив ячеек произвольного измерения, вы можете использовать CELLFUN, чтобы применить «my_func» к каждой ячейке:

    outArgs = cellfun(fcn,A);
    

    Функция "my_func" должна принимать A в качестве входа. Если есть какие-либо выходные данные из «my_func», они помещаются в outArgs , который будет того же размера / размера, что и A .

    Одна оговорка на выходах. , , если «my_func» возвращает выходные данные разных размеров и типов, когда он работает с различными элементами A , то outArgs придется преобразовать в массив ячеек. Это можно сделать, вызвав либо ARRAYFUN, либо CELLFUN с дополнительной парой параметр / значение:

    .
    outArgs = arrayfun(fcn,A,'UniformOutput',false);
    outArgs = cellfun(fcn,A,'UniformOutput',false);
    
    ответ дан gnovice, с репутацией 112908, 17.04.2009
  • 13 рейтинг

    Еще одна хитрость - использовать ind2sub и sub2ind. В сочетании с numel и size, это может позволить вам сделать что-то вроде следующего, который создает N-мерный массив, а затем устанавливает все элементы на «диагонали» равными 1.

    d = zeros( 3, 4, 5, 6 ); % Let's pretend this is a user input
    nel = numel( d );
    sz = size( d );
    szargs = cell( 1, ndims( d ) ); % We'll use this with ind2sub in the loop
    for ii=1:nel
        [ szargs{:} ] = ind2sub( sz, ii ); % Convert linear index back to subscripts
        if all( [szargs{2:end}] == szargs{1} ) % On the diagonal?
            d( ii ) = 1;
        end
    end
    
    ответ дан Edric, с репутацией 18659, 17.04.2009
  • 1 рейтинг

    эти решения быстрее (примерно на 11%), чем при использовании numel;)

    for idx = reshape(array,1,[]),
         element = element + idx;
    end
    

    или

    for idx = array(:)',
        element = element + idx;
    end
    

    UPD. tnx @rayryeng за обнаруженную ошибку в последнем ответе


    Отказ от ответственности

    Информация о сроках, на которую ссылалась эта запись, неверна и неточна из-за фундаментальной опечатки (см. Поток комментариев ниже, а также историю изменений - специально посмотрите на первую версию этого ответа). Предостережение Emptor .

    ответ дан mathcow, с репутацией 71, 8.04.2015
  • 1 рейтинг

    Вы могли бы сделать рекурсивную функцию сделать работу

    • Пусть L = size(M)
    • Пусть idx = zeros(L,1)
    • Возьмите length(L) в качестве максимальной глубины
    • Loop for idx(depth) = 1:L(depth)
    • Если ваша глубина length(L), выполните операцию элемента, иначе вызовите функцию снова с depth+1

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

    ответ дан Dennis Jaheruddin, с репутацией 16217, 15.11.2012
  • -1 рейтинг

    Если вы посмотрите глубже на другие варианты использования size, вы увидите, что вы можете получить вектор размера каждого измерения. Эта ссылка показывает вам документацию:

    www. MathWorks. ком / доступ / Служба поддержки / помощь / Techdoc / исх / размер. HTML

    Получив вектор размера, выполните итерацию по этому вектору. Примерно так (простите за мой синтаксис, так как я не использовал Matlab с колледжа):

    d = size(m);
    dims = ndims(m);
    for dimNumber = 1:dims
       for i = 1:d[dimNumber]
          ...
    

    Превратите это в настоящий синтаксис Matlab-Legal, и я думаю, что он будет делать то, что вы хотите.

    Кроме того, вы должны иметь возможность выполнять линейное индексирование, как описано здесь .

    ответ дан Erich Mirabal, с репутацией 8212, 17.04.2009
  • -1 рейтинг

    Вы хотите смоделировать n-вложенные циклы.

    Итерация по n-мерному массиву может рассматриваться как увеличение n-значного числа.

    В каждом измерении мы имеем столько цифр, сколько длина измерения.

    Пример:

    Предположим, у нас был массив (матрица)

    int[][][] T=new int[3][4][5];
    

    в «для обозначения» имеем:

    for(int x=0;x<3;x++)
       for(int y=0;y<4;y++)
           for(int z=0;z<5;z++)
              T[x][y][z]=...
    

    , чтобы смоделировать это, вы должны использовать «n-значный номер»

    У нас есть 3-значный номер, с 3-мя цифрами для первой, 4 для второй и пять для третьей цифры

    Нам нужно увеличить число, чтобы мы получили последовательность

    0 0 0
    0 0 1
    0 0 2    
    0 0 3
    0 0 4
    0 1 0
    0 1 1
    0 1 2
    0 1 3
    0 1 4
    0 2 0
    0 2 1
    0 2 2
    0 2 3
    0 2 4
    0 3 0
    0 3 1
    0 3 2
    0 3 3
    0 3 4
    and so on
    

    Таким образом, вы можете написать код для увеличения такого n-значного числа. Вы можете сделать это так, чтобы начать с любого значения числа и увеличивать / уменьшать цифры на любые числа. Таким образом, вы можете смоделировать вложенные циклы, которые начинаются где-то в таблице и заканчиваются не в конце.

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

    ответ дан bmegli, с репутацией 7, 10.03.2010