ฉันจะจัดทำดัชนีอาร์เรย์ MATLAB ที่ส่งกลับโดยฟังก์ชันโดยไม่กำหนดค่าให้กับตัวแปรโลคอลได้อย่างไร


363

ตัวอย่างเช่นถ้าฉันต้องการอ่านค่ากลางจากmagic(5)ฉันสามารถทำเช่นนี้:

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

value == 13ที่จะได้รับ ฉันต้องการที่จะสามารถทำสิ่งหนึ่งในสิ่งเหล่านี้:

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

เพื่อแจกจ่ายด้วยตัวแปรกลาง อย่างไรก็ตาม MATLAB บ่นเกี่ยวกับUnbalanced or unexpected parenthesis or bracketวงเล็บแรกก่อนหน้า3ในวงเล็บแรกก่อน

เป็นไปได้ไหมที่จะอ่านค่าจากอาเรย์ / เมทริกซ์โดยไม่ต้องกำหนดค่าให้กับตัวแปรก่อน


2
ฉันพบบทความต่อไปนี้ในชุดรูปแบบนี้: mathworks.com/matlabcentral/newsreader/view_thread/280225ใครมีข้อมูลใหม่เกี่ยวกับชุดรูปแบบนี้จะมีการใช้งานหรือไม่

2
ไวยากรณ์นี้ใช้งานได้จริงใน Octave ฉันค้นพบปัญหานี้เมื่อเพื่อนร่วมงานของฉันที่ใช้ MATLAB พบปัญหาในการเรียกใช้รหัสของฉันเท่านั้น
sffc

2
MATLAB สรุป
user76284

1
การสกัดแบบเรียกซ้ำยังทำงานใน Scilab ( scilab.org ) ตั้งแต่รุ่น 6
Stéphane Mottelet

ทั้งtestmatrix('magi', 5)(3, 3)Scilab และmagic(5)(3, 3)Octave ทั้งคู่ต่างทำงานกันอย่างมีเสน่ห์!
Foad

คำตอบ:


384

จริงๆแล้วมันเป็นไปได้ที่จะทำสิ่งที่คุณต้องการ แต่คุณต้องใช้รูปแบบการทำงานของตัวดำเนินการจัดทำดัชนี เมื่อคุณทำการดำเนินการจัดทำดัชนีโดยใช้()จริง ๆ แล้วคุณกำลังเรียกไปยังsubsrefฟังก์ชัน ดังนั้นแม้ว่าคุณจะจะไม่สามารถทำได้:

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

คุณ สามารถทำได้:

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

น่าเกลียด แต่เป็นไปได้ ;)

โดยทั่วไปคุณเพียงแค่ต้องเปลี่ยนขั้นตอนการจัดทำดัชนีเป็นการเรียกใช้ฟังก์ชันดังนั้นคุณจะไม่ต้องมีวงเล็บสองชุดที่อยู่ติดกันทันที อีกวิธีในการทำเช่นนี้ก็คือการกำหนดฟังก์ชั่นนิรนามของคุณเองเพื่อทำดัชนีห้อย ตัวอย่างเช่น:

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

แต่เมื่อทั้งหมดได้ถูกพูดและทำวิธีการแก้ปัญหาตัวแปรชั่วคราวท้องถิ่นมากเพิ่มเติมสามารถอ่านได้และแน่นอนสิ่งที่ผมอยากจะแนะนำ


26
คุณรู้อะไรดี! แม้ว่าฉันจะเห็นด้วยว่ามันน่าเกลียดและอาจอ่านได้น้อยกว่าโซลูชัน temp-var +1 สำหรับความรู้ MATLAB ที่น่าประทับใจ!
สอง

57
มันน่าขยะแขยง แต่เป็นคำตอบที่ชัดเจนมาก การทำงานที่ดี! ควรจะเดาได้เลยว่ามันจะต้องย้อนกลับไปหามัน ฉันจะคิดว่าฉันจะดำเนินการกับตัวแปรชั่วคราว
Joe Kearney

29
โปรดจำไว้ว่าตัวแปรกลางยังคงถูกสร้างขึ้นอย่างสมบูรณ์ ดังนั้นถ้าจุดประสงค์คือการบันทึกความทรงจำโดยไม่ต้องสร้างตัวแปรโลคอลชั่วคราวไม่มีโชค
Sam Roberts

8
@ SamRoberts: คุณไม่สามารถเข้าใจได้ในภาษาที่มีการประเมินอย่างเข้มงวดเช่น Matlab เหตุผลหลักที่ผู้คนต้องการนี่คือความรัดกุม / อ่านง่ายไม่ใช่การประหยัดหน่วยความจำ
หอยทากเครื่องกล

5
@SamRoberts: จริง แต่มันไม่ช่วยให้คุณประหยัดจากภาระในการโทรclearบนชั่วคราว (ซึ่งไม่มีใครไม่เคย) - ชั่วคราวมีแนวโน้มที่จะติดรอบอีกต่อไป
rody Oldenhuis

131

มีการโพสต์บล็อกที่ดีเกี่ยวกับLoren on the Art of Matlabเมื่อสองสามวันก่อนด้วยอัญมณีคู่ที่อาจช่วยได้ โดยเฉพาะอย่างยิ่งการใช้ฟังก์ชันตัวช่วยเช่น:

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

paren()สามารถใช้งานได้ที่ไหน

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

จะกลับมา

ans = 16

ฉันจะคาดการณ์ว่าจะเร็วกว่าคำตอบของ gnovice แต่ฉันไม่ได้ตรวจสอบ (ใช้ profiler !!!) ที่ถูกกล่าวว่าคุณยังต้องรวมคำนิยามฟังก์ชั่นเหล่านี้บางแห่ง โดยส่วนตัวฉันได้ทำให้พวกเขาทำหน้าที่เป็นอิสระในเส้นทางของฉันเพราะพวกเขามีประโยชน์มาก

ฟังก์ชั่นเหล่านี้และอื่น ๆ อยู่ในขณะนี้ที่มีอยู่ในการเขียนโปรแกรมโครงสร้างการทำงาน add-on ที่สามารถใช้ได้ผ่าน MATLAB Add-On Explorer หรือในไฟล์แลกเปลี่ยน


2
นี่เป็นรุ่นทั่วไปที่มากกว่าเล็กน้อยในช่วงครึ่งหลังของคำตอบของ gnovice; ดีเหมือนกัน.
Joe Kearney

เกี่ยวกับmyfunc().attrอะไร
gerrit

@gerrit ช่วยอะไรได้บ้าง? และฟิลด์ x.attr () ไม่สามารถใช้ได้เว้นแต่คุณจะมีกล่องเครื่องมือฐานข้อมูล
T. Furfaro

@ T.Furfaro Huh? หากmyfunc()ผลตอบแทนโครงสร้างที่มีแอตทริบิวต์attrแล้วในการเข้าถึงในขณะที่ฉันต้องทำattr S = myfunc(); S.attrคำถามคือถ้าเราสามารถมีฟังก์ชั่นผู้ช่วยเหมือนgetattr(myfunc(), 'attr')ในการเปรียบเทียบกับparenและcurlyผู้ช่วย ฉันไม่เข้าใจว่าสิ่งนี้เกี่ยวข้องกับกล่องเครื่องมือฐานข้อมูล
gerrit

2
@gerrit ขออภัยความสับสนทั้งหมด (ฉันไม่ทราบว่า "attr" ของคุณถูกกำหนดโดยพลการ - ใน db tb มีคำอธิบายฟิลด์กำหนดไว้) ฉันเชื่อว่าสิ่งที่คุณกำลังมองหาคือgetfield ()
T. Furfaro

75

คุณรู้สึกอย่างไรเกี่ยวกับการใช้คุณสมบัติที่ไม่มีเอกสาร:

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

หรือสำหรับอาร์เรย์เซลล์:

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

เหมือนเวทมนตร์ :)


UPDATE:

ข่าวร้ายแฮ็คข้างต้นไม่สามารถใช้งานได้ในR2015bอีกต่อไป! ไม่เป็นไรมันเป็นฟังก์ชั่นที่ไม่มีเอกสารและเราไม่สามารถไว้ใจได้ว่าเป็นคุณสมบัติที่รองรับ :)

fullfile(matlabroot,'bin','registry')สำหรับผู้ที่สงสัยว่าจะหาชนิดของสิ่งนี้ดูในโฟลเดอร์ มีไฟล์ XML อยู่มากมายที่แสดงรายการสารพัดทุกชนิด ถูกเตือนว่าการเรียกฟังก์ชั่นเหล่านี้โดยตรงอาจทำให้เซสชันของ MATLAB ของคุณเสียหายได้ง่าย


@RodyOldenhuis: I dont จำตอนนี้ผมคิดว่าผมจะต้องมีการอ่านมันในรหัสฝังบาง;)
Amro

2
ลำไส้ใหญ่ (:) ผู้ประกอบการจะต้องใช้ด้วย apostrophes เพื่อหลีกเลี่ยงข้อผิดพลาด':' Undefined function or variable "builtin"
Dominik

@Dominik: ถูกต้องว่าคุณต้องการแบ่งคอลัมน์ที่ 2 นั่นก็คือ: builtin('_paren', magic(5), ':', 2)(ในบางสถานที่มันทำงานได้โดยไม่ต้องมีใบเสนอราคาโดยตรง:ซึ่งต่างกับ':'เช่นเมื่อทำงานใน command prompt โดยตรงไม่ใช่จากฟังก์ชั่นฉันเดา นั่นเป็นข้อผิดพลาดใน parser!)
Amro

2
ฉันไม่คิดว่าจะมีวิธีใช้endกับสิ่งนี้หรือไม่?
knedlsepp

2
@knedlsepp: ไม่น่าเสียดายที่endเล่ห์เหลี่ยมทั้งหมดไม่ทำงานในไวยากรณ์นี้คุณจะต้องชัดเจนในการจัดทำดัชนีของคุณ .. (ข้อ จำกัด เดียวกันนี้ใช้กับคำตอบที่แสดงรายการอื่น ๆ ส่วนใหญ่)
Amro

54

อย่างน้อยใน MATLAB 2013a คุณสามารถใช้getfieldlike:

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

เพื่อรับองค์ประกอบที่ (1,2)


5
นี่เป็นวิธีที่ดีจริงๆ ข้อเสียใด ๆ
mmumboss

6
@mmumboss: นั่นเป็นพฤติกรรมที่ไม่มีเอกสารการทำงานนี้อาจหายไปโดยไม่ต้องแจ้งให้ทราบล่วงหน้าในอนาคต นอกจากนี้ไม่มีข้อเสีย
Daniel

6
ในฐานะของ MATLAB2017b ฟังก์ชั่นนี้ได้รับการบันทึกไว้
njspeer

15

น่าเสียดายที่ syntax like magic(5)(3,3)ไม่รองรับโดย matlab คุณต้องใช้ตัวแปรกลางชั่วคราว คุณสามารถเพิ่มหน่วยความจำหลังการใช้งานเช่น

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

12

โปรดทราบว่าหากคุณเปรียบเทียบเวลาการทำงานกับวิธีมาตรฐาน (กำหนดผลลัพธ์และเข้าถึงรายการ) สิ่งเหล่านี้จะเหมือนกันทุกประการ

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

ตามความเห็นของฉันบรรทัดล่างคือ: MATLAB ไม่มีพอยน์เตอร์คุณต้องอยู่กับมัน


6

มันอาจง่ายกว่านี้ถ้าคุณสร้างฟังก์ชั่นใหม่:

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

แล้วใช้มัน:

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

1
แต่นี่คือสิ่งที่subrefทำ ... แต่โดยทั่วไปมากกว่า
ไช

2
ใช่วิธีทั่วไปมากขึ้น แต่ไม่เป็นมิตร ... ที่น่าเกลียดมากในความคิดของฉัน
Vugar

4

สัญกรณ์เริ่มต้นของคุณเป็นวิธีที่รัดกุมที่สุดในการทำสิ่งนี้:

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

หากคุณทำเช่นนี้ในวงคุณสามารถกำหนด M ใหม่ทุกครั้งและเพิกเฉยต่อคำสั่งที่ชัดเจนเช่นกัน


6
ฉันยอมรับว่านี่เป็นข้อสรุปที่ชัดเจนมากขึ้นและการล้างข้อมูลเป็นความคิดที่ดีในการวนซ้ำตามที่คุณพูด แต่คำถามนี้เป็นคำถามเฉพาะว่าการหลีกเลี่ยงการมอบหมายกลางสามารถทำได้หรือไม่
Joe Kearney

1

เพื่อเติมเต็มคำตอบ Amro ของคุณสามารถใช้แทนfeval builtinไม่มีความแตกต่างจริงๆเว้นแต่คุณจะพยายามใช้งานฟังก์ชั่นการทำงานมากเกินไป:

BUILTIN (... ) เหมือนกันกับ FEVAL (... ) ยกเว้นว่ามันจะเรียกใช้ฟังก์ชั่นในตัวรุ่นดั้งเดิมถึงแม้ว่าจะมีฟังก์ชั่นโอเวอร์โหลดอยู่ (เพื่อให้สามารถใช้งานได้

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

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

สิ่งที่น่าสนใจก็คือfevalดูเหมือนว่าจะเร็วกว่าเล็กน้อยbuiltin(โดยประมาณ 3.5%) อย่างน้อยใน Matlab 2013b ซึ่งเป็นเรื่องแปลกเนื่องจากfevalต้องตรวจสอบว่าฟังก์ชั่นโอเวอร์โหลดแตกต่างจาก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.

จริงๆแล้วมันไม่แปลกเลย: MATLAB จะเก็บรายการฟังก์ชั่นที่กำหนดไว้ไม่มีการค้นหามากนัก fevalทำสิ่ง "ปกติ" และสามารถใช้ประโยชน์จากรายการนี้ได้อย่างเต็มที่ builtinจะต้องค้นหาที่อื่นเพื่อค้นหาฟังก์ชันที่สร้างขึ้นเท่านั้น กรณีนี้อาจไม่ได้รับการปรับให้เหมาะสมเกือบเท่ากับกรณี "ปกติ" เพราะเหตุใดคุณจึงนำเงินไปใช้ในการปรับปรุงบางสิ่งที่ไม่ได้ใช้บ่อยครั้ง
Cris Luengo
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.