私は問題があります。MATLABのn次元行列のすべての要素を反復処理する必要があります。問題は、任意の数の次元に対してこれを行う方法がわからないことです。私は私が言うことができることを知っています
for i = 1:size(m,1)
for j = 1:size(m,2)
for k = 1:size(m,3)
などですが、任意の数の次元に対してそれを行う方法はありますか?
私は問題があります。MATLABのn次元行列のすべての要素を反復処理する必要があります。問題は、任意の数の次元に対してこれを行う方法がわからないことです。私は私が言うことができることを知っています
for i = 1:size(m,1)
for j = 1:size(m,2)
for k = 1:size(m,3)
などですが、任意の数の次元に対してそれを行う方法はありますか?
線形インデックスを使用して各要素にアクセスできます。
for idx = 1:numel(array)
element = array(idx)
....
end
これは、現在の i、j、k を知る必要がない場合に便利です。ただし、現在のインデックスを知る必要がない場合は、おそらく arrayfun() を使用する方がよいでしょう
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
その結果、単一のループを使用して、一般的な nd 配列の各要素に順番にアクセスできます。たとえば、A の要素を 2 乗したい場合 (そうです、これを行うためのより良い方法があることは知っています)、次のようにすることができます。
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
線形インデックスの方が便利な状況はたくさんあります。線形インデックスと 2 次元 (またはそれ以上) の添字間の変換は、sub2ind および ind2sub 関数を使用して実行されます。
一般に、線形インデックスは matlab のすべての配列に適用されます。したがって、構造体、セル配列などで使用できます。線形インデックスの唯一の問題は、それらが大きくなりすぎた場合です。MATLAB は 32 ビット整数を使用してこれらのインデックスを格納します。したがって、配列に合計 2^32 要素を超える要素がある場合、線形インデックスは失敗します。これは、スパース行列を頻繁に使用する場合にのみ問題になりますが、これが問題を引き起こす場合があります。(私は 64 ビットの MATLAB リリースを使用していませんが、幸運にも 64 ビットの MATLAB リリースを使用した人は問題が解決したと思います。)
他のいくつかの回答で指摘されているように、単一の for ループでtoからの線形インデックスA
を使用して、(任意の次元の)行列内のすべての要素を反復処理できます。使用できる関数もいくつかあります:と.1
numel(A)
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
ます。
出力に関する 1 つの注意事項...my_func
の異なる要素を操作するときに異なるサイズと型の出力を返す場合はA
、outArgs
セル配列にする必要があります。arrayfun
これを行うには、次のいずれかを呼び出すかcellfun
、追加のパラメーター/値のペアを使用します。
outArgs = arrayfun(fcn, A, 'UniformOutput', false);
outArgs = cellfun(fcn, A, 'UniformOutput', false);
もう 1 つのトリックは、ind2sub
andを使用すること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
再帰関数を機能させることができます
L = size(M)
idx = zeros(L,1)
length(L)
最大深度とするfor idx(depth) = 1:L(depth)
length(L)
は要素操作を実行し、そうでない場合は関数を再度呼び出しますdepth+1
すべてのポイントをチェックしたい場合はベクトル化された方法ほど速くはありませんが、それらのほとんどを評価する必要がない場合は、かなりの時間を節約できます。
n-nestedforループをシミュレートしたいとします。
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桁の数字があり、1桁目は3桁、2桁目は4桁、3桁目は5桁です。
数を増やす必要があるので、シーケンスを取得します
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桁の数字を増やすためのコードを書くことができます。数字の任意の値から始めて、数字を任意の数字で増減できるようにすることができます。このようにして、テーブルのどこかで始まり、最後ではなく終了するネストされたforループをシミュレートできます。
ただし、これは簡単な作業ではありません。残念ながら、MATLAB表記を使用することはできません。
の他の使用法をsize
詳しく調べると、各次元のサイズのベクトルを実際に取得できることがわかります。このリンクはドキュメントを示しています:
www.mathworks.com/access/helpdesk/help/techdoc/ref/size.html
サイズ ベクトルを取得したら、そのベクトルを反復処理します。このようなもの(大学以来Matlabを使用していないため、私の構文を許してください):
d = size(m);
dims = ndims(m);
for dimNumber = 1:dims
for i = 1:d[dimNumber]
...
これを実際の Matlab に準拠した構文にすると、希望どおりになると思います。
また、ここで説明されているように、線形索引付けを実行できる必要があります。