Wie kann ich ein von einer Funktion zurückgegebenes MATLAB-Array indizieren, ohne es zuvor einer lokalen Variablen zuzuweisen?

363

Wenn ich beispielsweise den Mittelwert von lesen möchte magic(5), kann ich dies folgendermaßen tun:

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

zu bekommen value == 13. Ich möchte in der Lage sein, so etwas zu tun:

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

auf die Zwischenvariable verzichten. MATLAB beschwert sich jedoch über Unbalanced or unexpected parenthesis or bracketdie erste Klammer vor dem 3.

Ist es möglich, Werte aus einem Array / einer Matrix zu lesen, ohne sie zuvor einer Variablen zuzuweisen?

Joe Kearney
quelle
2
Ich habe auch den folgenden Artikel zu diesem Thema gefunden: mathworks.com/matlabcentral/newsreader/view_thread/280225 Hat jemand neue Informationen zu diesem Thema, wird es implementiert?
2
Diese Syntax funktioniert in Octave tatsächlich einwandfrei. Ich habe dieses Problem erst entdeckt, als meine Kollegen, die MATLAB verwenden, Probleme beim Ausführen meines Codes hatten.
sffc
2
MATLAB auf den Punkt gebracht.
user76284
1
Rekursive Extraktion funktioniert auch in Scilab ( scilab.org ) seit Version 6.
Stéphane Mottelet
Die testmatrix('magi', 5)(3, 3)auf Scilab und magic(5)(3, 3)auf Octave wirken beide wie ein Zauber!
Foad

Antworten:

384

Es tatsächlich ist möglich zu tun , was Sie wollen, aber Sie haben die funktionale Form des Indizierungsoperators verwenden. Wenn Sie eine Indizierungsoperation mit ausführen (), rufen Sie die subsrefFunktion tatsächlich auf . Also, obwohl Sie dies nicht tun können:

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

Sie können dies tun:

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

Hässlich, aber möglich. ;)

Im Allgemeinen müssen Sie nur den Indizierungsschritt in einen Funktionsaufruf ändern, damit nicht zwei Sätze von Klammern unmittelbar aufeinander folgen. Eine andere Möglichkeit, dies zu tun, besteht darin, eine eigene anonyme Funktion für die Indexierung zu definieren . Zum Beispiel:

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

Wenn alles gesagt und getan ist, ist die temporäre lokale Variablenlösung jedoch viel besser lesbar und definitiv das, was ich vorschlagen würde.

gnovice
quelle
26
Nun, was weißt du? obwohl ich damit einverstanden bin, ist es ziemlich hässlich und wahrscheinlich weniger lesbar als eine temporäre Lösung. +1 für beeindruckendes obskures Matlab-Wissen!
2.
57
Das ist widerlich, aber eine sehr klare Antwort. Gute Arbeit! Hätte raten sollen, dass es einen Rückweg geben würde. Ich denke, ich werde mit der temporären Variablen weitermachen.
Joe Kearney
29
Beachten Sie jedoch, dass die Zwischenvariable noch vollständig erstellt wurde. Wenn der Zweck darin besteht, Speicherplatz zu sparen, indem keine temporäre lokale Variable erstellt werden muss, ist dies kein Glück.
Sam Roberts
8
@SamRoberts: In einer Sprache mit strenger Bewertung wie Matlab kann man das nicht wirklich umgehen. Der Hauptgrund, warum die Leute dies wollen, ist Prägnanz / Lesbarkeit, nicht Speichereinsparungen.
Mechanische Schnecke
5
@SamRoberts: true, aber es tut sparen Sie von der Last der Aufruf clearüber die vorübergehende (was niemand jemals der Fall ist) - die temporäre neigt länger dableiben
Rody Oldenhuis
131

Es gab nur gute Blog - Post auf Loren auf der Art von Matlab ein paar Tagen mit ein paar Edelsteine , die helfen könnten. Insbesondere mit Hilfsfunktionen wie:

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

wo paren()kann wie verwendet werden

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

würde zurückkehren

ans = 16

Ich würde auch vermuten, dass dies schneller sein wird als die Antwort von gnovice, aber ich habe es nicht überprüft (Verwenden Sie den Profiler !!!). Davon abgesehen müssen Sie diese Funktionsdefinitionen auch irgendwo einfügen. Ich persönlich habe sie auf meinem Weg zu unabhängigen Funktionen gemacht, weil sie sehr nützlich sind.

Diese und andere Funktionen sind jetzt im Add-On für funktionale Programmierkonstrukte verfügbar, das über den MATLAB-Add-On-Explorer oder über den Dateiaustausch verfügbar ist .

T. Furfaro
quelle
2
Dies ist eine etwas allgemeinere Version der zweiten Hälfte der Antwort von gnovice; auch gut.
Joe Kearney
Was ist mit myfunc().attr?
Gerrit
@gerrit, wie hilft bei? und das Feld x.attr () ist nur verfügbar, wenn Sie über die Datenbank-Toolbox verfügen.
T. Furfaro
@ T.Furfaro Huh? Wenn myfunc()eine Struktur zurückgegeben wird, die ein Attribut enthält attr, muss attrich dies tun , um auf den aktuellen Zugriff zuzugreifen S = myfunc(); S.attr. Die Frage ist, ob wir eine Helferfunktion haben können, wie getattr(myfunc(), 'attr')in Analogie zu den parenund curlyHelfern. Ich verstehe nicht, was dies mit der Datenbank-Toolbox zu tun hat.
Gerrit
2
@gerrit Entschuldigung, völlige Verwirrung (mir war nicht bewusst, dass Ihr "attr" willkürlich war - in der Datenbank ist eine solche Feldexplizität definiert). Ich glaube, was Sie suchen, ist getfield ()
T. Furfaro
75

Wie stehen Sie zur Verwendung von undokumentierten Funktionen:

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

oder für Zellarrays:

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

Genau wie Magie :)


AKTUALISIEREN:

Schlechte Nachrichten, der obige Hack funktioniert in R2015b nicht mehr ! Das ist in Ordnung, es war eine undokumentierte Funktionalität und wir können uns nicht auf sie als unterstützte Funktion verlassen :)

Wenn Sie sich fragen, wo Sie solche Dinge finden können, schauen Sie im Ordner nach fullfile(matlabroot,'bin','registry'). Dort gibt es eine Reihe von XML-Dateien, in denen alle Arten von Extras aufgelistet sind. Seien Sie gewarnt, dass das direkte Aufrufen einiger dieser Funktionen Ihre MATLAB-Sitzung leicht zum Absturz bringen kann.

Amro
quelle
@RodyOldenhuis: Ich erinnere mich jetzt nicht, ich denke, ich muss es in einem vergrabenen Code gelesen haben;)
Amro
2
Der Doppelpunkt (:) muss mit Apostrophen verwendet werden ':', um den Fehler zu vermeiden Undefined function or variable "builtin".
Dominik
@Dominik: Richtig, sagen Sie, Sie möchten die 2. Spalte in Scheiben schneiden, das wäre: builtin('_paren', magic(5), ':', 2)(an bestimmten Stellen funktioniert es ohne die Anführungszeichen direkt :im Gegensatz zu ':', wie wenn Sie in der Eingabeaufforderung direkt und nicht innerhalb einer Funktion ausgeführt werden. Ich denke Das ist ein Fehler im Parser!)
Amro
2
Ich nehme nicht an, dass es eine Möglichkeit gibt, dies zu verwenden end?
Knedlsepp
2
@knedlsepp: Nein, leider endfunktioniert die ganze Trickerei in dieser Syntax nicht, Sie müssen in Ihrer Indizierung explizit sein. (Gleiche Einschränkung gilt für die meisten anderen aufgelisteten Antworten)
Amro
54

Zumindest in MATLAB 2013a können Sie Folgendes verwenden getfield:

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

um das Element bei (1,2) zu erhalten

Ian M. García
quelle
5
Dies ist eigentlich eine schöne Methode. Irgendwelche Nachteile?
mmumboss
6
@mmumboss: Dies ist ein undokumentiertes Verhalten. Diese Funktionalität wird möglicherweise in zukünftigen Versionen ohne vorherige Ankündigung ausgeblendet. Ansonsten keine Nachteile.
Daniel
6
Ab MATLAB2017b ist diese Funktionalität dokumentiert.
NJspeer
15

Leider wird syntax like magic(5)(3,3)von matlab nicht unterstützt. Sie müssen temporäre Zwischenvariablen verwenden. Sie können den Speicher nach Gebrauch freigeben, z

tmp = magic(3);
myVar = tmp(3,3);
clear tmp
zweite
quelle
12

Beachten Sie, dass wenn Sie die Laufzeiten mit der Standardmethode vergleichen (das Ergebnis zuordnen und dann auf Einträge zugreifen), diese genau gleich sind.

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

Meiner Meinung nach lautet das Fazit: MATLAB hat keine Zeiger, man muss damit leben.

Titus
quelle
6

Es könnte einfacher sein, wenn Sie eine neue Funktion erstellen:

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

und dann benutze es:

value = getElem(magic(5), 3, 3);
Vugar
quelle
1
aber genau das subrefmacht ... aber allgemeiner.
Shai
2
ja, allgemeiner, aber nicht freundlich ... meiner Meinung nach zu hässlich.
Vugar
4

Ihre anfängliche Notation ist der prägnanteste Weg, dies zu tun:

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

Wenn Sie dies in einer Schleife tun, können Sie M jedes Mal neu zuweisen und auch die klare Anweisung ignorieren.

Andreas GS
quelle
6
Ich stimme zu, dass dies prägnanter ist und das Löschen eine gute Idee in einer Schleife ist, wie Sie sagen, aber die Frage war speziell, ob die Zwischenzuweisung vermieden werden kann.
Joe Kearney
1

Um Amros Antwort zu ergänzen, können Sie fevalstattdessen anstelle von verwenden builtin. Es gibt wirklich keinen Unterschied, es sei denn, Sie versuchen, die Operatorfunktion zu überladen:

BUILTIN (...) ist dasselbe wie FEVAL (...), außer dass die ursprüngliche integrierte Version der Funktion aufgerufen wird, auch wenn eine überladene vorhanden ist (damit dies funktioniert, dürfen Sie BUILTIN niemals überladen).

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

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

Interessant ist, dass fevaldies builtinzumindest in Matlab 2013b nur ein kleines bisschen schneller zu sein scheint (um ~ 3,5%), was seltsam ist, da fevalüberprüft werden muss, ob die Funktion überlastet ist, im Gegensatz zu 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.
nirvana-msu
quelle
Es ist eigentlich nicht seltsam: MATLAB führt eine Liste definierter Funktionen, es gibt nicht so viel zu suchen. fevalmacht das "normale" Ding und kann daher diese Liste voll ausnutzen. builtinmuss woanders suchen, damit es nur eingebaute Funktionen findet. Wahrscheinlich ist dieser Fall nicht annähernd so stark optimiert wie der „normale“ Fall, denn warum sollten Sie Geld in die Optimierung von etwas stecken, das nicht sehr oft verwendet wird?
Cris Luengo