Làm cách nào tôi có thể lập chỉ mục một mảng MATLAB được trả về bởi một hàm mà không gán trước cho biến cục bộ?


363

Ví dụ: nếu tôi muốn đọc giá trị trung bình từ magic(5), tôi có thể làm như vậy:

M = magic(5);
value = M(3,3);

để có được value == 13. Tôi muốn có thể làm một cái gì đó giống như một trong những điều sau:

value = magic(5)(3,3);
value = (magic(5))(3,3);

để phân phối với các biến trung gian. Tuy nhiên, MATLAB phàn nàn về Unbalanced or unexpected parenthesis or bracketdấu ngoặc đơn đầu tiên trước dấu 3.

Có thể đọc các giá trị từ một mảng / ma trận mà không cần gán nó trước cho một biến không?


2
Tôi cũng tìm thấy bài viết sau đây về chủ đề này: mathworks.com/matlabcentral/newsreader/view_thread/280225 Bất kỳ ai cũng có thông tin mới về chủ đề này, liệu nó có được thực hiện không?

2
Cú pháp này thực sự hoạt động tốt trong Octave. Tôi chỉ phát hiện ra vấn đề này khi các đồng nghiệp sử dụng MATLAB gặp sự cố khi chạy mã của tôi.
sffc

2
MATLAB một cách ngắn gọn.
user76284

1
Trích xuất đệ quy cũng hoạt động trong Scilab ( scilab.org ) kể từ phiên bản 6.
Stéphane Mottelet

các testmatrix('magi', 5)(3, 3)trên Scilab và magic(5)(3, 3)trên Octave cả công việc như một nét duyên dáng!
Foad

Câu trả lời:


384

Nó thực sự có thể làm những gì bạn muốn, nhưng bạn phải sử dụng các hình thức chức năng của các nhà điều hành lập chỉ mục. Khi bạn thực hiện thao tác lập chỉ mục bằng cách sử dụng (), bạn thực sự đang thực hiện cuộc gọi đến subsrefhàm. Vì vậy, mặc dù bạn không thể làm điều này:

value = magic(5)(3, 3);

Bạn có thể làm điều này:

value = subsref(magic(5), struct('type', '()', 'subs', {{3, 3}}));

Xấu xí, nhưng có thể. ;)

Nói chung, bạn chỉ cần thay đổi bước lập chỉ mục thành lệnh gọi hàm để bạn không có hai bộ dấu ngoặc ngay sau nhau. Một cách khác để làm điều này là xác định hàm ẩn danh của riêng bạn để thực hiện lập chỉ mục được đăng ký. Ví dụ:

subindex = @(A, r, c) A(r, c);     % An anonymous function for 2-D indexing
value = subindex(magic(5), 3, 3);  % Use the function to index the matrix

Tuy nhiên, khi tất cả được nói và làm là giải pháp biến cục bộ tạm thời là nhiều hơn có thể đọc được, và chắc chắn những gì tôi sẽ đề nghị.


26
Vâng, những gì bạn biết không! mặc dù tôi đồng ý rằng nó khá xấu và có lẽ ít đọc hơn giải pháp temp-var. +1 cho kiến ​​thức matlab tối nghĩa ấn tượng!
thứ hai

57
Điều đó thật kinh tởm, nhưng một câu trả lời rất rõ ràng. Làm tốt lắm! Nên đoán rằng sẽ có một cách quay trở lại. Tôi sẽ nghĩ rằng tôi sẽ tiếp tục với biến tạm thời.
Joe Kearney

29
Hãy nhớ rằng biến trung gian vẫn được tạo hoàn toàn. Vì vậy, nếu mục đích là để tiết kiệm bộ nhớ bằng cách không phải tạo một biến cục bộ tạm thời, không có may mắn.
Sam Roberts

8
@SamRoberts: Bạn không thể thực sự hiểu được điều đó bằng ngôn ngữ đánh giá nghiêm ngặt như Matlab. Lý do chính khiến mọi người muốn điều này là sự đồng bộ / dễ đọc, không phải tiết kiệm bộ nhớ.
Ốc cơ khí

5
@SamRoberts: đúng, nhưng nó không giúp bạn tiết kiệm từ gánh nặng gọi cleartrên tạm thời (mà không ai bao giờ làm) - tạm thời có xu hướng dính vào xung quanh còn
Rody Oldenhuis

131

Chỉ có một bài đăng blog tốt về Loren trên Nghệ thuật Matlab vài ngày trước với một vài viên đá quý có thể giúp ích. Cụ thể, sử dụng các hàm trợ giúp như:

paren = @(x, varargin) x(varargin{:});
curly = @(x, varargin) x{varargin{:}};

nơi paren()có thể được sử dụng như

paren(magic(5), 3, 3);

sẽ trở lại

ans = 16

Tôi cũng sẽ phỏng đoán rằng điều này sẽ nhanh hơn câu trả lời của gnovice, nhưng tôi chưa kiểm tra (Sử dụng trình hồ sơ !!!). Điều đó đang được nói, bạn cũng phải bao gồm các định nghĩa chức năng ở đâu đó. Cá nhân tôi đã làm cho chúng hoạt động độc lập trong con đường của tôi, bởi vì chúng siêu hữu ích.

Các hàm này và các hàm khác hiện có sẵn trong phần bổ trợ Lập trình chức năng có sẵn thông qua Trình khám phá bổ trợ MATLAB hoặc trên Trao đổi tệp .


2
Đây là phiên bản chung hơn một chút của nửa sau câu trả lời của gnovice; cũng tốt.
Joe Kearney

Thế còn myfunc().attr?
gerrit

@gerrit, làm thế nào để giúp đỡ? và trường x.attr () không khả dụng trừ khi bạn có hộp công cụ cơ sở dữ liệu.
T. Furfaro

@ T.Furfaro Hả? Nếu myfunc()trả về một cấu trúc bao gồm một thuộc tính attr, thì để truy cập attrhiện tại tôi cần phải làm S = myfunc(); S.attr. Câu hỏi đặt ra là nếu chúng ta có thể có một hàm helper như getattr(myfunc(), 'attr')tương tự với các parencurlynhững người giúp đỡ. Tôi không hiểu điều này có liên quan đến hộp công cụ cơ sở dữ liệu.
gerrit

2
@gerrit Xin lỗi, sự nhầm lẫn hoàn toàn (Tôi không biết rằng "attr" của bạn là tùy ý - trong db tb có một giải thích trường được xác định như vậy). Tôi tin rằng những gì bạn đang tìm kiếm là getfield ()
T. Furfaro

75

Bạn cảm thấy thế nào về việc sử dụng các tính năng không có giấy tờ:

>> builtin('_paren', magic(5), 3, 3)               %# M(3,3)
ans =
    13

hoặc cho mảng di động:

>> builtin('_brace', num2cell(magic(5)), 3, 3)     %# C{3,3}
ans =
    13

Giống như phép thuật :)


CẬP NHẬT:

Tin xấu, bản hack trên không hoạt động nữa trong R2015b ! Điều đó tốt, đó là chức năng không có giấy tờ và chúng tôi không thể dựa vào nó như một tính năng được hỗ trợ :)

Đối với những người tự hỏi nơi để tìm loại điều này, tìm trong thư mục fullfile(matlabroot,'bin','registry'). Có một loạt các tệp XML liệt kê tất cả các loại quà tặng. Được cảnh báo rằng việc gọi trực tiếp một số chức năng này có thể dễ dàng làm sập phiên MATLAB của bạn.


@RodyOldenhuis: Bây giờ tôi không nhớ, tôi đoán là tôi đã đọc nó trong một số mã bị chôn vùi;)
Amro

2
Toán tử dấu hai chấm (:) phải được sử dụng với dấu nháy đơn ':'để tránh lỗi Undefined function or variable "builtin".
Dominik

@Dominik: đúng, giả sử bạn muốn cắt cột thứ 2, nghĩa là: builtin('_paren', magic(5), ':', 2)(ở một số nơi nó hoạt động mà không có trích dẫn trực tiếp :như trái ngược với ':', như khi chạy trong dấu nhắc lệnh không trực tiếp từ bên trong hàm. Tôi đoán đó là một lỗi trong trình phân tích cú pháp!)
Amro

2
Tôi không cho rằng có một số cách để sử dụng endvới điều này?
knedlsepp

2
@knedlsepp: Không, không may, toàn bộ end-trickery không hoạt động theo cú pháp này, bạn sẽ phải rõ ràng trong việc lập chỉ mục của mình .. (Giới hạn tương tự áp dụng cho hầu hết các câu trả lời được liệt kê khác)
Amro

54

Ít nhất trong MATLAB 2013a bạn có thể sử dụng getfieldnhư:

a=rand(5);
getfield(a,{1,2}) % etc

để lấy phần tử tại (1,2)


5
Đây thực sự là một phương pháp tốt đẹp. Bất kỳ nhược điểm?
mmumboss

6
@mmumboss: Đó là hành vi không có giấy tờ, chức năng này có thể biến mất mà không cần thông báo trong các phiên bản trong tương lai. Bên cạnh đó điều này không có nhược điểm.
Daniel

6
Kể từ MATLAB2017b, chức năng này được ghi lại.
njspeer

15

tiếc là cú pháp như magic(5)(3,3)không được hỗ trợ bởi MATLAB. bạn cần sử dụng các biến trung gian tạm thời. bạn có thể giải phóng bộ nhớ sau khi sử dụng, vd

tmp = magic(3);
myVar = tmp(3,3);
clear tmp

12

Lưu ý rằng nếu bạn so sánh thời gian chạy với cách tiêu chuẩn (căn chỉnh kết quả và sau đó truy cập các mục), chúng hoàn toàn giống nhau.

subs=@(M,i,j) M(i,j);
>> for nit=1:10;tic;subs(magic(100),1:10,1:10);tlap(nit)=toc;end;mean(tlap)

ans =

0.0103

>> for nit=1:10,tic;M=magic(100); M(1:10,1:10);tlap(nit)=toc;end;mean(tlap)

ans =

0.0101

Theo tôi, điểm mấu chốt là: MATLAB không có con trỏ, bạn phải sống với nó.


6

Nó có thể đơn giản hơn nếu bạn thực hiện một chức năng mới:

function [ element ] = getElem( matrix, index1, index2 )
    element = matrix(index1, index2);
end

và sau đó sử dụng nó:

value = getElem(magic(5), 3, 3);

1
nhưng đây chính xác là những gì subref... nhưng nói một cách tổng quát hơn.
Shai

2
vâng, cách tổng quát hơn, nhưng không thân thiện ... theo tôi là xấu xí.
Vugar

4

Ký hiệu ban đầu của bạn là cách ngắn gọn nhất để làm điều này:

M = magic(5);  %create
value = M(3,3);  % extract useful data
clear M;  %free memory

Nếu bạn đang làm điều này trong một vòng lặp, bạn chỉ có thể gán lại M mỗi lần và bỏ qua các tuyên bố rõ ràng.


6
Tôi đồng ý rằng điều này ngắn gọn hơn, và rõ ràng là một ý tưởng tốt trong một vòng lặp, như bạn nói, nhưng câu hỏi cụ thể là liệu có thể tránh được việc chuyển nhượng trung gian hay không.
Joe Kearney

1

Để bổ sung cho câu trả lời của Amro, bạn có thể sử dụng fevalthay vì builtin. Thực sự không có sự khác biệt, trừ khi bạn cố gắng làm quá tải hàm toán tử:

BUILTIN (...) giống như FEVAL (...) ngoại trừ việc nó sẽ gọi phiên bản dựng sẵn của chức năng ngay cả khi tồn tại một chức năng quá tải (để điều này hoạt động, bạn không bao giờ phải quá tải BUILTIN).

>> feval('_paren', magic(5), 3, 3)               % M(3,3)
ans =
    13

>> feval('_brace', num2cell(magic(5)), 3, 3)     % C{3,3}
ans =
    13

Điều thú vị là fevaldường như chỉ nhanh hơn một chút so với builtin(khoảng ~ 3,5%), ít nhất là trong Matlab 2013b, điều kỳ lạ được đưa ra là fevalcần kiểm tra xem chức năng có bị quá tải không, không giống như builtin:

>> tic; for i=1:1e6, feval('_paren', magic(5), 3, 3); end; toc;
Elapsed time is 49.904117 seconds.
>> tic; for i=1:1e6, builtin('_paren', magic(5), 3, 3); end; toc;
Elapsed time is 51.485339 seconds.

Nó thực sự không lạ: MATLAB giữ một danh sách các hàm được xác định, không có quá nhiều tìm kiếm để làm. fevalđiều bình thường của người Viking và do đó có thể sử dụng toàn bộ danh sách này. builtinphải tìm kiếm ở nơi khác để nó chỉ được tìm thấy trong các hàm. Có khả năng trường hợp này không được tối ưu hóa gần như trường hợp trên bình thường, vì tại sao bạn lại bỏ tiền vào việc tối ưu hóa một thứ không được sử dụng thường xuyên?
Cris Luengo
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.