wake-up-neo.com

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

Wenn ich zum Beispiel den mittleren Wert von magic(5) lesen möchte, kann ich dies folgendermaßen tun:

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

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 bracket in der ersten Klammer vor dem 3.

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

345
Joe Kearney

Es ist tatsächlich möglich zu tun, was Sie wollen, aber Sie müssen die funktionale Form des Indexierungsoperators verwenden. Wenn Sie eine Indizierungsoperation mit () Ausführen, rufen Sie tatsächlich die Funktion subsref auf. Also, obwohl du kann nicht das machst:

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

Sie können tun dies:

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 Klammern unmittelbar aufeinander folgen. Eine andere Möglichkeit, dies zu tun, besteht darin, Ihre eigene anonyme Funktion zu definieren, um die Indexierung durchzuführen. Beispielsweise:

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

Aber wenn alles gesagt und getan ist, ist die temporäre Lösung für lokale Variablen much besser lesbar und definitiv das, was ich vorschlagen würde.

372
gnovice

Es gab gerade guter Blog-Beitrag am Loren über die Kunst von Matlab vor ein paar Tagen mit ein paar Juwelen, die vielleicht helfen könnten. Insbesondere mit Hilfsfunktionen wie:

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

dabei kann paren() wie folgt verwendet werden

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

würden 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 (Benutze den Profiler !!!). Allerdings müssen Sie diese Funktionsdefinitionen auch irgendwo einfügen. Ich persönlich habe sie auf meinem Weg zu eigenständigen Funktionen gemacht, weil sie super nützlich sind.

Diese und andere Funktionen sind jetzt im Add-On Functional Programming Constructs verfügbar, das über den MATLAB Add-On Explorer oder im Dateiaustausch .

128
T. Furfaro

Wie stehen Sie zu 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 nicht mehr in R2015b! Das ist in Ordnung, es war undokumentierte Funktionalität und wir können uns nicht darauf als unterstützte Funktion verlassen :)

Wenn Sie sich fragen, wo Sie diese Art von Dingen finden, schauen Sie in den Ordner fullfile(matlabroot,'bin','registry'). Dort gibt es eine Reihe von XML-Dateien, in denen alle Arten von Goodies aufgelistet sind. Seien Sie gewarnt, dass der direkte Aufruf einiger dieser Funktionen leicht zu einem Absturz Ihrer MATLAB-Sitzung führen kann.

75
Amro

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

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

um das Element auf (1,2) zu bekommen

53
Ian M. García

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

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

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

[email protected](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.

12
titus

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);
6
Vugar

Ihre anfängliche Notation ist der präziseste 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 einfach jedes Mal M neu zuweisen und die klare Anweisung ebenfalls ignorieren.

4
Andreas GS

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

BUILTIN (...) ist dasselbe wie FEVAL (...), mit der Ausnahme, dass es die ursprüngliche integrierte Version der Funktion aufruft, 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 feval, zumindest in Matlab 2013b, nur ein kleines bisschen schneller zu sein scheint als builtin (um ~ 3,5%), was seltsam ist, wenn man bedenkt, dass feval benötigt um zu überprüfen, ob die Funktion im Gegensatz zu builtin überladen ist:

>> 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.
1
nirvana-msu