MATLAB'da n boyutlu bir matristeki her bir elemanı nasıl yinelerim?


87

Bir problemim var. MATLAB'da n boyutlu bir matristeki her öğeyi yinelemem gerekiyor. Sorun şu ki, keyfi sayıda boyut için bunu nasıl yapacağımı bilmiyorum. Biliyorum söyleyebilirim

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

ve benzeri, ancak bunu keyfi sayıda boyut için yapmanın bir yolu var mı?


13
Matlab terminoloji notu: Matlab'ın az sayıda temel veri türü vardır. En önemlileri şunlardır: yapı, matris ve hücre dizisi. Bir matrisin parçalarına atıfta bulunurken, "eleman" terimini kullanmak ve "hücre" terimini bir hücre dizisinin parçalarına atıfta bulunmak için ayırmak yaygındır. Hücre dizileri ve matrisleri, her ikisi de N boyutlu veri yapıları olsa da, sayısız sözdizimsel ve anlamsal farklılıklara sahiptir.
Bay Fooz

3
Yinelemeye ne için ihtiyacınız olduğunu sorabilir miyim? Belki de bunu yapmanın "vektörleştirilmiş" bir yolu vardır ...
Hosam Aly

Yanıtlar:


92

Her bir öğeye erişmek için doğrusal indekslemeyi kullanabilirsiniz.

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

Bu, i, j, k, nerede olduğunuzu bilmenize gerek yoksa yararlıdır. Bununla birlikte, hangi dizinde olduğunuzu bilmeniz gerekmiyorsa, muhtemelen arrayfun () kullanmanız daha iyi olur.


1
Herhangi bir nedenden dolayı endekslerini kurtarmak istiyorsa Ayrıca, yine de bu iki basit komutları kullanarak olabilir: I = cell(1, ndims(array)); [I{:}] = ind2sub(size(array),idx);.
knedlsepp

34

Matlab'deki diziler için doğrusal indeks fikri önemli bir fikirdir. MATLAB'daki bir dizi gerçekten belleğe dizilmiş bir eleman vektörüdür. MATLAB, bir satır ve sütun dizini veya tek bir doğrusal dizin kullanmanıza izin verir. Örneğin,

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

A(2,3)
ans =
     7

A(8)
ans =
     7

Diziyi bir vektöre açarak elemanların bellekte saklanma sırasını görebiliriz.

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

Gördüğünüz gibi, 8. eleman 7 sayısıdır. Aslında, find işlevi sonuçlarını doğrusal bir dizin olarak döndürür.

find(A>6)
ans =
     1
     6
     8

Sonuç olarak, her bir elemana tek bir döngü kullanarak genel bir nd dizisi ile erişebiliriz. Örneğin, A'nın öğelerini karelemek istersek (evet, bunu yapmanın daha iyi yolları olduğunu biliyorum), bunu yapabiliriz:

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

Doğrusal indeksin daha kullanışlı olduğu birçok durum vardır. Doğrusal indeks ile iki (veya daha yüksek) boyutlu alt simge arasındaki dönüşüm, alt2ind ve ind2sub fonksiyonları ile gerçekleştirilir.

Doğrusal indeks genel olarak matlab'deki herhangi bir dizi için geçerlidir. Yani bunu yapılar, hücre dizileri vb. Üzerinde kullanabilirsiniz. Doğrusal indeksle ilgili tek sorun, çok büyüdükleri zamandır. MATLAB, bu dizinleri saklamak için 32 bitlik bir tamsayı kullanır. Dolayısıyla, dizinizde toplam 2 ^ 32'den fazla öğe varsa, doğrusal dizin başarısız olur. Seyrek matrisleri sık sık kullanırsanız bu gerçekten sadece bir sorundur, bazen bu bir soruna neden olur. (64 bit MATLAB sürümü kullanmasam da, bu sorunun, kullanan şanslı kişiler için çözüldüğüne inanıyorum.)


64-bit MATLAB'de indeksleme gerçekten de 64-bit aboneliklere doğru şekilde izin verir. Örneğin: x = ones(1,2^33,'uint8'); x(2^33)beklendiği gibi çalışır.
Edric

@Edric - Tabii ki, bu açıklamayı yaptığımdan beri yıllar içinde (ve birçok sürümde) kesinlikle değişecek bir davranış. Yine de kontrol ettiğiniz için teşekkürler.

:) Yorum yapana kadar cevabın kaç yaşında olduğunu bilmiyordum - soru RSS beslememde belirdi ve ben de cevapladığımı fark etmedim bile!
Edric

15

Birkaç diğer yanıtlar belirttiği gibi, bir matris içinde tüm unsurları adımlayabilirsiniz Abir kullanarak (herhangi bir boyutun) doğrusal endeksi gelen 1için numel(A)döngü için tek yer. Ayrıca kullanabileceğiniz birkaç işlev vardır: arrayfunve cellfun.

İlk olarak, A(çağrılan my_func) öğesinin her bir öğesine uygulamak istediğiniz bir işleve sahip olduğunuzu varsayalım . Önce bu işlev için bir işlev tutamacı oluşturursunuz :

fcn = @my_func;

Eğer A(çift vb tek tipte) keyfi boyutun bir matris, sen kullanabilirsiniz arrayfunuygulamak için my_funcher elemana:

outArgs = arrayfun(fcn, A);

Eğer Abir olan hücreli dizi keyfi boyutun kullanabileceğiniz cellfunuygulamak için my_funcher hücreye:

outArgs = cellfun(fcn, A);

Fonksiyonun bir girdi olarak my_funckabul etmesi gerekir A. Herhangi bir çıktı varsa my_func, bunlar outArgsaynı boyutta / boyutta olacak şekilde yerleştirilir A.

Çıktılarda bir uyarı ... my_funcfarklı elemanlar üzerinde çalışırken farklı boyut ve türlerde çıktılar döndürürse A, o outArgszaman bir hücre dizisine yapılmalıdır. Bu, çağrılarak arrayfunveya cellfunek bir parametre / değer çifti ile yapılır:

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

13

Bir diğer hile kullanmaktır ind2subve sub2ind. İle birlikte numelve sizebu, N boyutlu bir dizi oluşturur ve daha sonra 1 olmak "diyagonal" tüm unsurları belirleyen aşağıdaki gibi şeyler yapalım yapabilirsiniz.

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

MATLAB'ın ördek yazmayı nasıl bozduğuna dair güzel bir örnek için +1.
Phillip Bulut

1

Özyinelemeli bir işlevin işini yapmasını sağlayabilirsiniz

  • İzin Vermek L = size(M)
  • İzin Vermek idx = zeros(L,1)
  • length(L)Maksimum derinlik olarak alın
  • Döngü for idx(depth) = 1:L(depth)
  • Derinliğiniz ise length(L), eleman işlemini yapın, aksi takdirde fonksiyonu ile tekrar çağırın.depth+1

Tüm noktaları kontrol etmek istiyorsanız, vektörleştirilmiş yöntemler kadar hızlı değil, ancak çoğunu değerlendirmeniz gerekmiyorsa, bu oldukça zaman kazandırabilir.


1

bu çözümler kullanmaktan daha hızlıdır (yaklaşık% 11) numel;)

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

veya

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

UPD. tnx @rayryeng son yanıtta tespit edilen hata için


Feragatname

Bu gönderinin referans verdiği zamanlama bilgileri, yapılan temel bir yazım hatası nedeniyle yanlış ve yanlıştır (aşağıdaki yorum akışının yanı sıra düzenleme geçmişine bakın - özellikle bu cevabın ilk versiyonuna bakın). Caveat Emptor .


1
1 : array(:)eşdeğerdir 1 : array(1). Bu, tüm unsurlarda yineleme yapmaz, bu nedenle çalışma süreleriniz hızlıdır. Dahası, kayan noktalı sayılar randüretir ve bunu yapmak , ifadeniz, başlangıç ​​değeri 1 olan artan bir vektör bulmaya çalışırken boş bir dizi üretir ve artan bir aralıkta bir kayan nokta sayısı olarak bir son değeri olan 1 1'in adımları. Boş bir vektörle sonuçlanan böyle bir olası vektör yoktur. Kişisel döngü çalışmaz ve böylece iddiası yanlıştır. -1 oy. afedersiniz. 1 : array(:)[0,1)for
rayryeng

@rayryeng haklı değilsin. dizi (:), 1: dizi (1) ile eşdeğer değildir. Seviyor reshape(...).
mathcow

@rayryeng matlab r2013a + linux - işe yarıyor! ;) Ben de bu kodu çalıştırdım
mathcow

Üzerinde yazın 1 : array(:)oluşturduktan sonra komut isteminde array . Boş bir matris aldın mı? evet ise, kodunuz çalışmaz. Oyumu bırakıyorum çünkü yanlış bilgi veriyorsunuz.
rayryeng

@rayryeng anlıyorum! evet, haklısın, aptalca anlaşmazlık için özür dilerim
mathcow

-1

Diğer kullanımlarına daha derin bakarsanız size, aslında her boyutun boyutunun bir vektörünü elde edebileceğinizi görebilirsiniz. Bu bağlantı size belgeleri gösterir:

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

Boyut vektörünü aldıktan sonra, bu vektör üzerinde yineleyin. Bunun gibi bir şey (üniversiteden beri Matlab'ı kullanmadığım için sözdizimimi bağışlayın):

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

Bunu gerçek Matlab-yasal sözdizimi haline getirin ve bence istediğinizi yapacaktır.

Ayrıca, burada açıklandığı gibi Doğrusal İndeksleme yapabilmelisiniz .


Döngülerin sıralanmasının bir matrisin tüm öğeleri üzerinde nasıl yinelendiğini tam olarak anlayamıyorum. Örneğin, 3'e 4 matrisiniz varsa (12 elemanlı), iç döngünüz yalnızca 7 kez yinelenecektir.
gnovice

matrisin her bir boyutu üzerinde yinelenmelidir. Dış döngü boyut üzerinde, iç döngü bu boyutun boyutu üzerinde yinelenir. En azından fikir bu. Herkesin belirttiği gibi, tek istediği her bir hücre ise, astar indeksleme en iyisidir. Her bir boyutu tekrarlamak istiyorsa, buna benzer bir şey yapması gerekecektir.
Erich Mirabal

ayrıca, düzenlediğiniz için teşekkürler. Bağlantım biraz karışıktı ve normal bağlantı yöntemini kullanarak düzgün çalışmıyordu. Ayrıca, ifademi genişletmek için: yine de dizinin diğer birçok takibini yapması gerekecekti (bir sayaç veya benzeri bir şey kullanarak). Bence sen veya Andrew'un yaklaşımı onun yapmaya çalıştığını düşündüğüm şey için daha kolay olurdu.
Erich Mirabal

-1

İç içe geçmiş döngüleri simüle etmek istiyorsunuz.

N boyutlu dizide yineleme, n basamaklı sayıyı arttırmak olarak görülebilir.

Her boyutta, boyutun uzunluğu kadar basamağa sahibiz.

Misal:

Dizimiz (matris) olduğunu varsayalım

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

"gösterim için" de var:

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

bunu simüle etmek için "n basamaklı sayı gösterimi" kullanmanız gerekir

Birincisi 3, ikinci için 4 ve üçüncü basamak için beş olmak üzere 3 basamaklı sayımız var

Sayıyı artırmalıyız, böylece diziyi elde ederiz

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

Böylece bu n basamaklı sayıyı artırmak için kod yazabilirsiniz. Sayının herhangi bir değeri ile başlayıp basamakları herhangi bir sayı ile artırıp / azaltabileceğiniz şekilde yapabilirsiniz. Bu şekilde, tablonun bir yerinde başlayan ve sonunda bitmeyen döngüler için iç içe geçmiş döngüleri simüle edebilirsiniz.

Yine de bu kolay bir iş değil. Maalesef matlab notasyonu konusunda yardımcı olamıyorum.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.