Làm cách nào để lặp qua từng phần tử trong ma trận n chiều trong MATLAB?


87

Tôi có một vấn đề. Tôi cần lặp lại mọi phần tử trong ma trận n chiều trong MATLAB. Vấn đề là, tôi không biết làm thế nào để làm điều này cho một số thứ nguyên tùy ý. Tôi biết tôi có thể nói

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

vân vân, nhưng có cách nào để làm điều đó cho một số kích thước tùy ý không?


13
Lưu ý về thuật ngữ Matlab: Matlab có một số lượng nhỏ các kiểu dữ liệu cốt lõi. Quan trọng nhất là: struct, matrix và cell array. Khi đề cập đến các phần của ma trận, người ta thường sử dụng thuật ngữ "phần tử" và dành thuật ngữ "ô" để chỉ các phần của một mảng ô. Mảng ô và ma trận có nhiều khác biệt về cú pháp và ngữ nghĩa, mặc dù cả hai đều là cấu trúc dữ liệu N chiều.
Mr Fooz

3
Tôi có thể hỏi bạn cần lặp lại để làm gì không? Có thể có một "vector" cách để làm điều đó thay vì ...
Hosam Aly

Câu trả lời:


92

Bạn có thể sử dụng lập chỉ mục tuyến tính để truy cập từng phần tử.

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

Điều này rất hữu ích nếu bạn không cần biết tôi, j, k, bạn đang ở đâu. Tuy nhiên, nếu bạn không cần biết mình đang ở chỉ mục nào, có lẽ bạn nên sử dụng arrayfun ()


1
Ngoài ra, nếu bạn muốn khôi phục lại các chỉ số đối với một số lý do nào, bạn vẫn có thể sử dụng hai lệnh đơn giản: I = cell(1, ndims(array)); [I{:}] = ind2sub(size(array),idx);.
knedlsepp

34

Ý tưởng về một chỉ số tuyến tính cho các mảng trong matlab là một ý tưởng quan trọng. Một mảng trong MATLAB thực sự chỉ là một vector gồm các phần tử, được xâu chuỗi trong bộ nhớ. MATLAB cho phép bạn sử dụng chỉ mục hàng và cột hoặc chỉ mục tuyến tính duy nhất. Ví dụ,

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

A(2,3)
ans =
     7

A(8)
ans =
     7

Chúng ta có thể thấy thứ tự các phần tử được lưu trong bộ nhớ bằng cách cuộn mảng thành một vector.

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

Như bạn có thể thấy, phần tử thứ 8 là số 7. Trên thực tế, hàm find trả về kết quả của nó dưới dạng một chỉ số tuyến tính.

find(A>6)
ans =
     1
     6
     8

Kết quả là chúng ta có thể truy cập lần lượt từng phần tử của mảng thứ n tổng quát bằng một vòng lặp đơn. Ví dụ: nếu chúng ta muốn bình phương các phần tử của A (vâng, tôi biết có nhiều cách tốt hơn để làm điều này), người ta có thể làm điều này:

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

Có nhiều trường hợp mà chỉ số tuyến tính hữu ích hơn. Việc chuyển đổi giữa chỉ số tuyến tính và hai (hoặc cao hơn) chỉ số con chiều được thực hiện với các hàm sub2ind và ind2sub.

Chỉ số tuyến tính áp dụng chung cho bất kỳ mảng nào trong matlab. Vì vậy, bạn có thể sử dụng nó trên các cấu trúc, mảng ô, v.v. Vấn đề duy nhất với chỉ mục tuyến tính là khi chúng quá lớn. MATLAB sử dụng một số nguyên 32 bit để lưu trữ các chỉ mục này. Vì vậy, nếu mảng của bạn có nhiều hơn tổng cộng 2 ^ 32 phần tử trong đó, thì chỉ mục tuyến tính sẽ không thành công. Nó thực sự chỉ là một vấn đề nếu bạn sử dụng ma trận thưa thớt thường xuyên, đôi khi điều này sẽ gây ra sự cố. (Mặc dù tôi không sử dụng bản phát hành MATLAB 64 bit, nhưng tôi tin rằng vấn đề đó đã được giải quyết cho những người may mắn.)


Lập chỉ mục trong MATLAB 64 bit thực sự cho phép các chỉ số con 64 bit một cách chính xác. Ví dụ: x = ones(1,2^33,'uint8'); x(2^33)hoạt động như mong đợi.
Edric

@Edric - Tất nhiên, đây là một hành vi chắc chắn sẽ thay đổi trong nhiều năm (và nhiều bản phát hành) kể từ khi tôi đưa ra tuyên bố đó. Cảm ơn đã kiểm tra mặc dù.

:) Tôi đã không nhận ra câu trả lời cũ bao nhiêu cho đến khi tôi nhận xét - câu hỏi vừa xuất hiện trong nguồn cấp dữ liệu RSS của tôi, và tôi thậm chí không nhận thấy rằng tôi cũng đã trả lời nó!
Edric

15

Như đã chỉ ra trong một số câu trả lời khác, bạn có thể lặp lại trên tất cả các phần tử trong ma trận A(với bất kỳ thứ nguyên nào) bằng cách sử dụng chỉ số tuyến tính từ 1đến numel(A)trong một vòng lặp for duy nhất. Ngoài ra còn có một số chức năng bạn có thể sử dụng: arrayfuncellfun.

Trước tiên, hãy giả sử bạn có một hàm mà bạn muốn áp dụng cho từng phần tử của A(được gọi my_func). Trước tiên, bạn tạo một hàm xử lý cho hàm này:

fcn = @my_func;

Nếu Alà ma trận (loại kép, đơn, v.v.) có thứ nguyên tùy ý, bạn có thể sử dụng arrayfunđể áp dụng my_funccho từng phần tử:

outArgs = arrayfun(fcn, A);

Nếu Alà một mảng ô có kích thước tùy ý, bạn có thể sử dụng cellfunđể áp dụng my_funccho từng ô:

outArgs = cellfun(fcn, A);

Hàm my_funcphải chấp nhận Anhư một đầu vào. Nếu có bất kỳ đầu ra nào từ my_func, chúng sẽ được đặt vào outArgs, sẽ có cùng kích thước / thứ nguyên với A.

Một lưu ý về kết quả đầu ra ... nếu my_functrả về kết quả đầu ra có kích thước và kiểu khác nhau khi nó hoạt động trên các phần tử khác nhau của A, thì outArgssẽ phải được tạo thành một mảng ô. Điều này được thực hiện bằng cách gọi một trong hai arrayfunhoặc cellfunvới một cặp tham số / giá trị bổ sung:

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

13

Một thủ thuật khác là sử dụng ind2subsub2ind. Kết hợp với numelsize, điều này có thể cho phép bạn thực hiện những việc như sau, tạo một mảng N chiều, sau đó đặt tất cả các phần tử trên "đường chéo" là 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

+1 để hiển thị một ví dụ điển hình về cách MATLAB phá vỡ cách gõ vịt.
Phillip Cloud

1

Bạn có thể làm cho một hàm đệ quy thực hiện công việc

  • Để cho L = size(M)
  • Để cho idx = zeros(L,1)
  • Lấy length(L)độ sâu tối đa
  • Vòng for idx(depth) = 1:L(depth)
  • Nếu độ sâu của bạn là length(L), hãy thực hiện thao tác phần tử, nếu không, hãy gọi lại hàm bằngdepth+1

Không nhanh như các phương pháp vectơ hóa nếu bạn muốn kiểm tra tất cả các điểm, nhưng nếu bạn không cần đánh giá hầu hết chúng, nó có thể khá tiết kiệm thời gian.


1

những giải pháp này nhanh hơn (khoảng 11%) so với việc sử dụng numel;)

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

hoặc là

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

CẬP NHẬT. tnx @rayryeng cho lỗi được phát hiện trong câu trả lời cuối cùng


Khước từ

Thông tin thời gian mà bài đăng này đã tham chiếu không chính xác và không chính xác do lỗi đánh máy cơ bản (xem luồng nhận xét bên dưới cũng như lịch sử chỉnh sửa - cụ thể là xem phiên bản đầu tiên của câu trả lời này). Cảnh báo trước .


1
1 : array(:)tương đương với 1 : array(1). Điều này không lặp lại qua tất cả các yếu tố, đó là lý do tại sao thời gian chạy của bạn nhanh chóng. Hơn nữa, randtạo các số dấu phẩy động và làm như vậy 1 : array(:)sẽ tạo ra một mảng trống vì câu lệnh của bạn đang cố gắng tìm một vectơ tăng dần với giá trị ban đầu là 1 với giá trị kết thúc là số dấu phẩy động với phạm vi [0,1)không bao gồm 1 đang tăng dần các bước của 1. Không có vectơ khả dĩ như vậy, dẫn đến vectơ rỗng. forVòng lặp của bạn không chạy và do đó yêu cầu của bạn là sai. -1 phiếu bầu. lấy làm tiếc.
rayryeng

@rayryeng bạn không đúng. array (:) không tương đương với 1: array (1). Nó thích reshape(...).
mathcow

@rayryeng matlab r2013a + linux - nó hoạt động! ;) Tôi cũng vừa chạy mã đó
mathcow

Nhập vào 1 : array(:)dấu nhắc lệnh của bạn sau khi tạo array . Bạn có nhận được một ma trận trống không? nếu có thì mã của bạn không hoạt động. Tôi bỏ phiếu bầu vì bạn đang đưa ra thông tin sai lệch.
rayryeng

@rayryeng tôi hiểu rồi! vâng, bạn là đúng, xin lỗi vì tranh chấp ngu ngốc
mathcow

-1

Nếu bạn nhìn sâu hơn vào các cách sử dụng khác của nó, sizebạn có thể thấy rằng bạn thực sự có thể nhận được một vectơ có kích thước của mỗi chiều. Liên kết này hiển thị cho bạn tài liệu:

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

Sau khi nhận được vectơ kích thước, hãy lặp lại vectơ đó. Một cái gì đó như thế này (xin lỗi cú pháp của tôi vì tôi đã không sử dụng Matlab kể từ khi học đại học):

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

Biến điều này thành cú pháp Matlab-legal thực tế và tôi nghĩ nó sẽ làm được những gì bạn muốn.

Ngoài ra, bạn sẽ có thể thực hiện Lập chỉ mục tuyến tính như được mô tả ở đây .


Tôi không thể hiểu được thứ tự các vòng lặp đó sẽ lặp lại như thế nào trên tất cả các phần tử của ma trận. Ví dụ: nếu bạn có ma trận 3 x 4 (với 12 phần tử), vòng lặp bên trong của bạn sẽ chỉ lặp lại 7 lần.
gnovice

nó sẽ lặp lại trên từng thứ nguyên của ma trận. Có nghĩa là vòng lặp bên ngoài lặp lại trên kích thước, vòng lặp bên trong trên kích thước của thứ nguyên đó. Ít nhất, đó là ý tưởng. Như mọi người khác đang nói, nếu tất cả những gì anh ấy muốn là từng ô, thì tốt nhất là lập chỉ mục lót. Nếu anh ta muốn lặp lại từng chiều, anh ta sẽ phải làm điều gì đó tương tự như thế này.
Erich Mirabal

Ngoài ra, cảm ơn đã chỉnh sửa. liên kết của tôi hơi phức tạp và sẽ không hoạt động bình thường nếu sử dụng cách liên kết thông thường. Ngoài ra, để mở rộng tuyên bố của tôi: anh ta vẫn sẽ phải thực hiện nhiều việc theo dõi chỉ mục khác (sử dụng như một bộ đếm hoặc một cái gì đó tương tự). Tôi nghĩ bạn hoặc cách tiếp cận của Andrew sẽ dễ dàng hơn cho những gì tôi nghĩ anh ấy đang cố gắng làm.
Erich Mirabal

-1

Bạn muốn mô phỏng n vòng lặp for lồng nhau.

Lặp lại qua mảng n-dimmensional có thể được coi là tăng số n chữ số.

Tại mỗi chiều mờ, chúng ta có bao nhiêu chữ số bằng chiều dài của chiều mờ.

Thí dụ:

Giả sử chúng ta có mảng (ma trận)

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

trong "for notation" chúng ta có:

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

để mô phỏng điều này, bạn sẽ phải sử dụng "ký hiệu số gồm n chữ số"

Chúng ta có 3 chữ số, với 3 chữ số đầu tiên, 4 chữ số thứ hai và năm chữ số thứ ba

Chúng tôi phải tăng số lượng, vì vậy chúng tôi sẽ nhận được chuỗi

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

Vì vậy, bạn có thể viết mã để tăng số n chữ số như vậy. Bạn có thể làm điều đó theo cách mà bạn có thể bắt đầu với bất kỳ giá trị nào của số và tăng / giảm các chữ số theo bất kỳ số nào. Bằng cách đó, bạn có thể mô phỏng các vòng lặp for lồng nhau bắt đầu ở đâu đó trong bảng và kết thúc không phải ở cuối.

Đây không phải là một nhiệm vụ dễ dàng. Tôi không thể giúp gì với phân tích ký hiệu matlab.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.