Bagaimana cara melakukan iterasi melalui setiap elemen dalam matriks n-dimensi di MATLAB?

87

Saya punya masalah. Saya perlu mengulang melalui setiap elemen dalam matriks n-dimensi di MATLAB. Masalahnya adalah, saya tidak tahu bagaimana melakukan ini untuk jumlah dimensi yang berubah-ubah. Saya tahu saya bisa mengatakannya

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

dan seterusnya, tetapi apakah ada cara untuk melakukannya untuk jumlah dimensi yang berubah-ubah?

rlbond.dll
sumber
13
Catatan terminologi Matlab: Matlab memiliki sejumlah kecil tipe data inti. Yang paling penting adalah: struct, matrix, dan cell array. Saat merujuk ke bagian matriks, istilah "elemen" biasanya digunakan, dan menggunakan istilah "sel" untuk merujuk ke bagian larik sel. Larik dan matriks sel memiliki banyak perbedaan sintaksis dan semantik, meskipun keduanya merupakan struktur data berdimensi-N.
Tuan Fooz
3
Bolehkah saya bertanya untuk apa Anda membutuhkan iterasi? Mungkin ada cara "vektor" untuk melakukannya ...
Hosam Aly

Jawaban:

92

Anda dapat menggunakan pengindeksan linier untuk mengakses setiap elemen.

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

Ini berguna jika Anda tidak perlu tahu apa i, j, k, Anda. Namun, jika Anda tidak perlu mengetahui indeks Anda, Anda mungkin lebih baik menggunakan arrayfun ()

Andrew
sumber
1
Juga, jika Anda ingin memulihkan indeks untuk beberapa alasan, Anda masih bisa menggunakan dua perintah sederhana ini: I = cell(1, ndims(array)); [I{:}] = ind2sub(size(array),idx);.
knedlsepp
34

Ide indeks linier untuk array di matlab adalah satu hal yang penting. Array dalam MATLAB sebenarnya hanyalah sebuah vektor elemen, dirangkai dalam memori. MATLAB memungkinkan Anda menggunakan indeks baris dan kolom, atau indeks linier tunggal. Sebagai contoh,

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

A(2,3)
ans =
     7

A(8)
ans =
     7

Kita dapat melihat urutan elemen disimpan dalam memori dengan membuka gulungan array menjadi vektor.

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

Seperti yang Anda lihat, elemen ke-8 adalah angka 7. Faktanya, fungsi find mengembalikan hasilnya sebagai indeks linier.

find(A>6)
ans =
     1
     6
     8

Hasilnya adalah, kita dapat mengakses setiap elemen secara bergiliran dari array nd umum menggunakan satu loop. Misalnya, jika kita ingin mengkuadratkan elemen A (ya, saya tahu ada cara yang lebih baik untuk melakukan ini), seseorang dapat melakukan ini:

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

Ada banyak situasi di mana indeks linier lebih berguna. Konversi antara indeks linier dan dua (atau lebih tinggi) dimensi subskrip dilakukan dengan fungsi sub2ind dan ind2sub.

Indeks linier berlaku secara umum untuk semua larik di matlab. Jadi Anda bisa menggunakannya pada struktur, array sel, dll. Satu-satunya masalah dengan indeks linier adalah ketika indeks terlalu besar. MATLAB menggunakan integer 32 bit untuk menyimpan indeks ini. Jadi jika array Anda memiliki lebih dari total 2 ^ 32 elemen di dalamnya, indeks linier akan gagal. Ini benar-benar hanya menjadi masalah jika Anda sering menggunakan matriks renggang, padahal terkadang hal ini akan menyebabkan masalah. (Meskipun saya tidak menggunakan rilis MATLAB 64 bit, saya percaya bahwa masalah tersebut telah diselesaikan untuk orang-orang yang beruntung yang melakukannya.)


sumber
Pengindeksan dalam MATLAB 64-bit memang memungkinkan langganan 64-bit dengan benar. Misalnya: x = ones(1,2^33,'uint8'); x(2^33)berfungsi seperti yang diharapkan.
Edric
@Edric - Tentu saja, ini adalah perilaku yang pasti akan berubah selama bertahun-tahun (dan banyak rilis) sejak saya membuat pernyataan itu. Terima kasih sudah memeriksanya.
:) Saya tidak menyadari berapa umur jawabannya sampai setelah saya berkomentar - pertanyaan itu baru saja muncul di RSS feed saya, dan saya bahkan tidak menyadari bahwa saya telah menjawabnya juga!
Edric
15

Seperti yang ditunjukkan dalam beberapa jawaban lain, Anda dapat mengulang semua elemen dalam matriks A(dari dimensi apa pun) menggunakan indeks linier dari 1ke numel(A)dalam satu perulangan for. Ada juga beberapa fungsi yang dapat Anda gunakan: arrayfundan cellfun.

Mari kita asumsikan pertama Anda memiliki fungsi yang ingin Anda terapkan ke setiap elemen A(dipanggil my_func). Anda pertama kali membuat tuas fungsi untuk fungsi ini:

fcn = @my_func;

Jika Amerupakan matriks (tipe double, single, dll.) Dengan dimensi arbitrer, Anda dapat menggunakan arrayfununtuk diterapkan my_funcke setiap elemen:

outArgs = arrayfun(fcn, A);

Jika Aadalah larik sel dengan dimensi arbitrer, Anda dapat menggunakan cellfununtuk diterapkan my_funcke setiap sel:

outArgs = cellfun(fcn, A);

Fungsi my_functersebut harus menerima Asebagai masukan. Jika ada keluaran dari my_func, ini ditempatkan di outArgs, yang akan memiliki ukuran / dimensi yang sama seperti A.

Satu peringatan pada output ... jika my_funcmengembalikan output dengan ukuran dan tipe berbeda ketika beroperasi pada elemen yang berbeda A, maka outArgsharus dibuat menjadi array sel. Ini dilakukan dengan memanggil salah satu arrayfunatau cellfundengan pasangan parameter / nilai tambahan:

outArgs = arrayfun(fcn, A, 'UniformOutput', false);
outArgs = cellfun(fcn, A, 'UniformOutput', false);
gnovice
sumber
13

Trik lainnya adalah menggunakan ind2subdan sub2ind. Dalam hubungannya dengan numeldan size, ini memungkinkan Anda melakukan hal-hal seperti berikut, yang membuat larik berdimensi-N, dan kemudian menyetel semua elemen pada "diagonal" menjadi 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
sumber
1 untuk menunjukkan contoh yang baik tentang bagaimana MATLAB memecahkan pengetikan bebek.
Phillip Cloud
1

Anda bisa membuat fungsi rekursif bekerja

  • Membiarkan L = size(M)
  • Membiarkan idx = zeros(L,1)
  • Ambil length(L)sebagai kedalaman maksimal
  • Loop for idx(depth) = 1:L(depth)
  • Jika kedalaman Anda length(L), lakukan operasi elemen, jika tidak, panggil fungsi lagi dengandepth+1

Tidak secepat metode vektor jika Anda ingin memeriksa semua poin, tetapi jika Anda tidak perlu mengevaluasi sebagian besar dari mereka, ini bisa menghemat waktu.

Dennis Jaheruddin
sumber
1

solusi ini lebih cepat (sekitar 11%) daripada menggunakan numel;)

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

atau

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

UPD. tnx @rayryeng untuk kesalahan yang terdeteksi dalam jawaban terakhir


Penolakan

Informasi waktu yang dirujuk posting ini salah dan tidak akurat karena kesalahan ketik mendasar yang dibuat (lihat aliran komentar di bawah serta riwayat edit - secara khusus lihat versi pertama dari jawaban ini). Caveat Emptor .

mathcow
sumber
1
1 : array(:)setara dengan 1 : array(1). Ini tidak mengulangi semua elemen, itulah sebabnya waktu kerja Anda cepat. Selain itu, randmenghasilkan angka floating-point , dan hal itu 1 : array(:)akan menghasilkan larik kosong karena pernyataan Anda mencoba menemukan vektor yang meningkat dengan nilai awalnya sebagai 1 dengan nilai akhir sebagai angka floating-point dengan kisaran [0,1)eksklusif 1 dalam peningkatan langkah-langkah 1. Tidak ada vektor yang memungkinkan, yang menghasilkan vektor kosong. Anda forloop tidak dijalankan, sehingga klaim Anda adalah palsu. -1 suara. Maaf.
rayryeng
@rayryeng Anda tidak benar. array (:) tidak sama dengan 1: array (1). Itu suka reshape(...).
mathcow
@rayryeng matlab r2013a + linux - berhasil! ;) Saya baru saja menjalankan kode itu juga
mathcow
Ketik 1 : array(:)di command prompt Anda setelah membuat array . Apakah Anda mendapatkan matriks kosong? jika ya maka kode Anda tidak berfungsi. Saya meninggalkan suara saya karena Anda memberikan informasi palsu.
rayryeng
@rayryeng saya mengerti! ya, Anda benar, maaf atas perselisihan yang bodoh
mathcow
-1

Jika Anda melihat lebih dalam kegunaan lain dari sizeAnda dapat melihat bahwa Anda sebenarnya bisa mendapatkan vektor ukuran setiap dimensi. Tautan ini menunjukkan dokumentasi kepada Anda:

www.mathworks.com/access/helpdesk/help/techdoc/ref/size.html

Setelah mendapatkan vektor ukuran, lakukan iterasi pada vektor tersebut. Sesuatu seperti ini (maafkan sintaks saya karena saya tidak menggunakan Matlab sejak kuliah):

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

Jadikan ini menjadi sintaks Matlab-legal yang sebenarnya, dan saya pikir itu akan melakukan apa yang Anda inginkan.

Selain itu, Anda harus dapat melakukan Pengindeksan Linear seperti yang dijelaskan di sini .

Erich Mirabal
sumber
Saya tidak bisa melihat bagaimana pengurutan loop akan mengulangi semua elemen matriks. Misalnya, jika Anda memiliki matriks 3-kali-4 (dengan 12 elemen), loop dalam Anda hanya akan melakukan iterasi 7 kali.
gnovice
itu harus mengulangi setiap dimensi matriks. Loop luar melakukan iterasi terhadap dimensi, loop dalam melebihi ukuran dimensi itu. Setidaknya, itulah idenya. Seperti yang dikatakan orang lain, jika yang dia inginkan hanyalah setiap sel, pengindeksan liner adalah yang terbaik. Jika dia ingin mengulang setiap dimensi, dia harus melakukan sesuatu yang serupa dengan ini.
Erich Mirabal
juga, terima kasih telah mengedit. link saya agak berbelit-belit dan tidak akan berfungsi dengan benar menggunakan cara menghubungkan yang biasa. Juga, untuk memperluas pernyataan saya: dia masih harus melakukan banyak pelacakan indeks lainnya (menggunakan seperti penghitung atau semacamnya). Saya pikir pendekatan Anda atau Andrew akan lebih mudah untuk apa yang saya pikir dia coba lakukan.
Erich Mirabal
-1

Anda ingin mensimulasikan n-bersarang untuk loop.

Iterasi melalui larik n-dimensi dapat dilihat sebagai peningkatan angka n-digit.

Pada setiap dimensi kita memiliki digit sebanyak panjang dimensi tersebut.

Contoh:

Misalkan kita memiliki array (matriks)

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

dalam "untuk notasi" kita memiliki:

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]=...

untuk mensimulasikan ini, Anda harus menggunakan "notasi angka n-digit"

Kami memiliki 3 digit angka, dengan 3 digit untuk pertama, 4 untuk kedua dan lima untuk digit ketiga

Kita harus menambah angkanya, jadi kita akan mendapatkan urutannya

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

Jadi Anda dapat menulis kode untuk meningkatkan angka n-digit tersebut. Anda dapat melakukannya sedemikian rupa sehingga Anda dapat memulai dengan nilai apa pun dari nomor tersebut dan menambah / mengurangi digit dengan angka apa pun. Dengan begitu, Anda dapat mensimulasikan loop bersarang yang dimulai di suatu tempat di tabel dan tidak selesai di akhir.

Ini bukanlah tugas yang mudah. Saya tidak dapat membantu dengan notasi matlab sayangnya.

bmegli.dll
sumber