Mam problem. Muszę iterować przez każdy element w n-wymiarowej macierzy w MATLAB-ie. Problem w tym, że nie wiem, jak to zrobić dla dowolnej liczby wymiarów. Wiem, że mogę powiedzieć
for i = 1:size(m,1)
for j = 1:size(m,2)
for k = 1:size(m,3)
i tak dalej, ale czy jest sposób, aby to zrobić dla dowolnej liczby wymiarów?
Odpowiedzi:
Aby uzyskać dostęp do każdego elementu, można użyć indeksowania liniowego.
for idx = 1:numel(array) element = array(idx) .... end
Jest to przydatne, jeśli nie musisz wiedzieć, na czym jesteś i, j, k. Jeśli jednak nie musisz wiedzieć, w jakim indeksie się znajdujesz, prawdopodobnie lepiej będzie użyć funkcji arrayfun ()
źródło
I = cell(1, ndims(array)); [I{:}] = ind2sub(size(array),idx);
.Idea liniowego indeksu dla tablic w Matlabie jest ważna. Tablica w MATLABie jest w rzeczywistości wektorem elementów ułożonych w pamięci. MATLAB pozwala na użycie indeksu wierszy i kolumn lub pojedynczego indeksu liniowego. Na przykład,
A = magic(3) A = 8 1 6 3 5 7 4 9 2 A(2,3) ans = 7 A(8) ans = 7
Możemy zobaczyć kolejność elementów przechowywanych w pamięci, rozwijając tablicę do wektora.
A(:) ans = 8 3 4 1 5 9 6 7 2
Jak widać, ósmy element to liczba 7. W rzeczywistości funkcja find zwraca swoje wyniki jako indeks liniowy.
find(A>6) ans = 1 6 8
W rezultacie możemy uzyskać dostęp do każdego elementu po kolei z ogólnej tablicy nd za pomocą pojedynczej pętli. Na przykład, gdybyśmy chcieli podnieść do kwadratu elementy A (tak, wiem, że są na to lepsze sposoby), można to zrobić:
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
Istnieje wiele okoliczności, w których wskaźnik liniowy jest bardziej przydatny. Konwersja między indeksem liniowym a dwoma (lub wyższymi) wymiarowymi indeksami dolnymi odbywa się za pomocą funkcji sub2ind i ind2sub.
Indeks liniowy ma zastosowanie ogólnie do dowolnej tablicy w programie MATLAB. Możesz więc używać go na strukturach, tablicach komórek itp. Jedyny problem z indeksem liniowym polega na tym, że stają się zbyt duże. MATLAB używa 32-bitowej liczby całkowitej do przechowywania tych indeksów. Więc jeśli twoja tablica ma więcej niż łącznie 2 ^ 32 elementów, indeks liniowy zawiedzie. Tak naprawdę jest to problem tylko wtedy, gdy często używasz rzadkich macierzy, gdy czasami powoduje to problem. (Chociaż nie używam 64-bitowej wersji MATLAB, uważam, że problem został rozwiązany dla tych szczęśliwców, którzy to robią.)
źródło
x = ones(1,2^33,'uint8'); x(2^33)
działa zgodnie z oczekiwaniami.Jak wskazano w kilku innych odpowiedziach, możesz iterować po wszystkich elementach macierzy
A
(o dowolnym wymiarze), używając indeksu liniowego od1
donumel(A)
w pojedynczej pętli for. Istnieje również kilka funkcji, których możesz użyć:arrayfun
icellfun
.Załóżmy najpierw, że masz funkcję, którą chcesz zastosować do każdego elementu
A
(nazwanegomy_func
). Najpierw tworzysz uchwyt funkcji do tej funkcji:Jeśli
A
jest to macierz (typu double, single, itp.) O dowolnym wymiarze, możesz zastosowaćarrayfun
jąmy_func
do każdego elementu:Jeśli
A
jest to tablica komórek o dowolnym wymiarze, możesz zastosowaćcellfun
jąmy_func
do każdej komórki:outArgs = cellfun(fcn, A);
Funkcja
my_func
musi akceptowaćA
jako dane wejściowe. Jeśli są jakieś wyjścia zmy_func
, są one umieszczane woutArgs
, które będą miały taki sam rozmiar / wymiar jakA
.Jedno zastrzeżenie dotyczące danych wyjściowych ... jeśli
my_func
zwraca dane wyjściowe o różnych rozmiarach i typach, gdy działa na różnych elementach programuA
,outArgs
będzie musiało zostać przekształcone w tablicę komórek. Odbywa się to poprzez wywołanie jednejarrayfun
lubcellfun
dodatkowej pary parametr / wartość:outArgs = arrayfun(fcn, A, 'UniformOutput', false); outArgs = cellfun(fcn, A, 'UniformOutput', false);
źródło
Jeszcze jedna sztuczka polega na użyciu
ind2sub
isub2ind
. W połączeniu znumel
isize
pozwala to na wykonanie takich czynności, jak poniższe, które tworzą tablicę N-wymiarową, a następnie ustawiają wszystkie elementy na „przekątnej” na 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
źródło
Możesz sprawić, że funkcja rekurencyjna będzie działać
L = size(M)
idx = zeros(L,1)
length(L)
jako maksymalną głębokośćfor idx(depth) = 1:L(depth)
length(L)
, wykonaj operację elementu, w przeciwnym razie wywołaj funkcję ponownie za pomocądepth+1
Nie tak szybko jak metody wektoryzowane, jeśli chcesz sprawdzić wszystkie punkty, ale jeśli nie musisz oceniać większości z nich, może to znacznie zaoszczędzić czas.
źródło
te rozwiązania są szybsze (ok. 11%) niż przy użyciu
numel
;)for idx = reshape(array,1,[]), element = element + idx; end
lub
for idx = array(:)', element = element + idx; end
UPD. tnx @rayryeng dla wykrycia błędu w ostatniej odpowiedzi
Zrzeczenie się
Informacje o czasie, do których odwołuje się ten post, są niepoprawne i niedokładne z powodu fundamentalnej literówki (zobacz strumień komentarzy poniżej, a także historię zmian - spójrz w szczególności na pierwszą wersję tej odpowiedzi). Caveat Emptor .
źródło
1 : array(:)
jest równoważne1 : array(1)
. To nie powoduje iteracji przez wszystkie elementy, dlatego czasy wykonywania są szybkie. Ponadtorand
generuje liczby zmiennoprzecinkowe , co1 : array(:)
spowodowałoby powstanie pustej tablicy, ponieważ instrukcja próbuje znaleźć rosnący wektor o wartości początkowej równej 1 z wartością końcową jako liczbą zmiennoprzecinkową z zakresem[0,1)
wykluczającym 1 w zwiększaniu kroki z 1. Nie ma takiego możliwego wektora, co skutkuje pustym wektorem. Twojafor
pętla nie działa, więc twoje twierdzenie jest fałszywe. -1 głos. Przepraszam.reshape(...)
.1 : array(:)
w wierszu polecenia po utworzeniuarray
. Czy otrzymujesz pustą matrycę? jeśli tak, to twój kod nie działa. Zostawiam mój głos, ponieważ podaje Pan fałszywe informacje.Jeśli przyjrzysz się
size
bliżej innym zastosowaniom , zobaczysz, że w rzeczywistości możesz uzyskać wektor wielkości każdego wymiaru. Ten link pokazuje dokumentację:www.mathworks.com/access/helpdesk/help/techdoc/ref/size.html
Po uzyskaniu wektora rozmiaru wykonaj iterację po tym wektorze. Coś takiego (przepraszam za moją składnię, ponieważ nie korzystałem z Matlab od czasów studiów):
d = size(m); dims = ndims(m); for dimNumber = 1:dims for i = 1:d[dimNumber] ...
Zrób to w rzeczywistej składni Matlab-legalnej i myślę, że zrobi to, co chcesz.
Powinieneś także być w stanie przeprowadzić indeksowanie liniowe zgodnie z opisem tutaj .
źródło
Chcesz symulować n-zagnieżdżone pętle for.
Iterowanie przez tablicę n-wymiarową można postrzegać jako zwiększenie liczby n-cyfrowej.
Na każdym wymiarze mamy tyle cyfr, ile jest długości wymiaru.
Przykład:
Załóżmy, że mamy tablicę (macierz)
int[][][] T=new int[3][4][5];
w "do notacji" mamy:
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]=...
aby to zasymulować, musiałbyś użyć „notacji liczby n-cyfrowej”
Mamy trzycyfrową liczbę, z 3 cyframi na pierwszą, 4 na drugą i pięcioma na trzecią
Musimy zwiększyć liczbę, aby uzyskać sekwencję
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
Możesz więc napisać kod zwiększający taką n-cyfrową liczbę. Możesz to zrobić w taki sposób, że możesz zacząć od dowolnej wartości liczby i zwiększać / zmniejszać cyfry o dowolne liczby. W ten sposób można symulować zagnieżdżone pętle, które zaczynają się gdzieś w tabeli, a kończą nie na końcu.
Nie jest to jednak łatwe zadanie. Nie mogę pomóc z notacją Matlab niestety.
źródło