Kartenfunktion in MATLAB?

100

Ich bin ein wenig überrascht, dass MATLAB keine Map-Funktion hat, also habe ich selbst eine gehackt, da es etwas ist, ohne das ich nicht leben kann. Gibt es da draußen eine bessere Version? Gibt es eine etwas standardmäßige funktionale Programmierbibliothek für MATLAB, die mir fehlt?

function results = map(f,list)
% why doesn't MATLAB have a Map function?
results = zeros(1,length(list));
for k = 1:length(list)
    results(1,k) = f(list(k));
end

end

Verwendung wäre zB

map( @(x)x^2,1:10)
Will Ness
quelle
12
Lektion 1 von anderen Sprachen zu Matlab: Nicht für Schleifen verwenden, sie sind einige Größenordnungen langsamer als eine vektorisierte Lösung.
CookieOfFortune
15
Mit der Einführung der JIT erhalten for-Schleifen nicht die Strafe, die sie einmal hatten.
MatlabDoug
@ CookieOfFortune Ich denke, das ist nicht mehr wahr ...
Ander Biguri
2
@AnderBiguri Ich denke, sie haben einige Verbesserungen hinzugefügt, aber es ist immer noch viel langsamer.
CookieOfFortune
Die Funktionsbibliothek auf File Exchange hat map, foldl(auch bekannt als reduce), select(aka filter) und andere unentbehrliche Leckereien. Empfohlen (wenn Sie Matlab verwenden müssen).
Ahmed Fasih

Antworten:

133

Die kurze Antwort: Die integrierte Funktion arrayfunmacht genau das, was Ihre mapFunktion für numerische Arrays macht:

>> y = arrayfun(@(x) x^2, 1:10)
y =

     1     4     9    16    25    36    49    64    81   100

Es gibt zwei weitere integrierte Funktionen, die sich ähnlich verhalten: cellfun(die auf Elemente von Zellenarrays angewendet werden) und structfun(die auf jedem Feld einer Struktur ausgeführt werden).

Diese Funktionen sind jedoch häufig nicht erforderlich, wenn Sie die Vektorisierung nutzen, insbesondere mit elementweisen arithmetischen Operatoren . Für das von Ihnen angegebene Beispiel wäre eine vektorisierte Lösung:

>> x = 1:10;
>> y = x.^2
y =

     1     4     9    16    25    36    49    64    81   100

Einige Operationen werden automatisch über Elemente hinweg ausgeführt (z. B. das Hinzufügen eines Skalarwerts zu einem Vektor), während andere Operatoren eine spezielle Syntax für die elementweise Operation haben (gekennzeichnet durch a .vor dem Operator). Viele in MATLAB integrierte Funktionen sind so konzipiert, dass sie Vektor- und Matrixargumente mit elementweisen Operationen verarbeiten (häufig auf eine bestimmte Dimension angewendet, wie z. B. sumund mean), und erfordern daher keine Kartenfunktionen.

Zusammenfassend gibt es hier verschiedene Möglichkeiten, um jedes Element in einem Array zu quadrieren:

x = 1:10;       % Sample array
f = @(x) x.^2;  % Anonymous function that squares each element of its input

% Option #1:
y = x.^2;  % Use the element-wise power operator

% Option #2:
y = f(x);  % Pass a vector to f

% Option #3:
y = arrayfun(f, x);  % Pass each element to f separately

Für eine so einfache Operation ist Option 1 natürlich die sinnvollste (und effizienteste) Wahl.

gnovice
quelle
2
Man sollte beachten, dass Option 1 nicht nur einfacher, sondern auch schneller ist (im Vergleich zu Option 3 sollte 2 1 sehr ähnlich sein)!
Diederick C. Niehorster
10

Neben vektor- und elementweisen Operationen gibt es auch cellfunFunktionen zum Zuordnen von Funktionen über Zellenarrays. Beispielsweise:

cellfun(@upper, {'a', 'b', 'c'}, 'UniformOutput',false)
ans = 
    'A'    'B'    'C'

Wenn 'UniformOutput' true ist (oder nicht bereitgestellt wird), wird versucht, die Ergebnisse entsprechend den Abmessungen des Zellenarrays zu verketten

cellfun(@upper, {'a', 'b', 'c'})
ans =
ABC
Kwatford
quelle
2

Eine ziemlich einfache Lösung unter Verwendung der Vektorisierung von Matlab wäre:

a = [ 10 20 30 40 50 ]; % the array with the original values
b = [ 10 8 6 4 2 ]; % the mapping array
c = zeros( 1, 10 ); % your target array

Nun tippen

c( b ) = a

kehrt zurück

c = 0    50     0    40     0    30     0    20     0    10

c (b) ist eine Referenz auf einen Vektor der Größe 5 mit den Elementen von c an den durch b gegebenen Indizes. Wenn Sie nun diesem Referenzvektor Werte zuweisen, werden die ursprünglichen Werte in c überschrieben, da c (b) Verweise auf die Werte in c und keine Kopien enthält.

doc
quelle
1

Es scheint, dass das eingebaute Arrayfun nicht funktioniert, wenn das benötigte Ergebnis ein Funktionsarray ist: zB: map (@ (x) [xx ^ 2 x ^ 3], 1: 10)

leichte Mods unten machen diese Arbeit besser:

function results = map(f,list)
% why doesn't MATLAB have a Map function?
for k = 1:length(list)
    if (k==1)
        r1=f(list(k));
        results = zeros(length(r1),length(list));
        results(:,k)=r1;
    else
        results(:,k) = f(list(k));

    end;
end;
end
Foo Bara
quelle
5
ARRAYFUN würde für Ihr Beispiel funktionieren. Sie müssten nur die Eingabeargumente einschließen ..., 'UniformOutput', false);, um eine Zellenarray-Ausgabe zu erstellen, die Ihre Arrays enthält, und sie dann formatieren und kombinieren, wie Sie möchten, zu einem Nicht-Zellenarray.
Gnovice
0

Wenn matlab keine integrierte Kartenfunktion hat, kann dies an Effizienzüberlegungen liegen. In Ihrer Implementierung verwenden Sie eine Schleife, um die Elemente der Liste zu durchlaufen, was in der Matlab-Welt im Allgemeinen verpönt ist. Die meisten integrierten Matlab-Funktionen sind "vektorisiert", dh es ist effizienter, eine Funktion für ein gesamtes Array aufzurufen, als sie selbst zu durchlaufen und die Funktion für jedes Element aufzurufen.

Mit anderen Worten, dies


a = 1:10;
a.^2

ist viel schneller als das


a = 1:10;
map(@(x)x^2, a)

unter der Annahme Ihrer Definition der Karte.

Dima
quelle
2
Ich denke, sein Punkt war nicht, dass er wollte, dass es notwendigerweise eine Schleife ist, sondern einfach so spezifiziert wird, dass das Ergebnisarray der Anwendung der bereitgestellten Funktion auf entsprechende Elemente des gelieferten Arrays als Ergebnis vorliegt. Ich weiß nicht viel Matlab, aber es scheint, dass Arrayfun den Job macht.
1
Die meisten integrierten Matlab-Funktionen und -Operatoren tun dies bereits: Sie arbeiten mit jedem Element des Eingabearrays und geben ein entsprechendes Ergebnisarray zurück.
Dima
0

Sie brauchen nicht, mapda eine Skalarfunktion, die auf eine Werteliste angewendet wird, auf jeden der Werte angewendet wird und daher ähnlich funktioniert wie map. Probier's einfach

l = 1:10
f = @(x) x + 1

f(l)

In Ihrem speziellen Fall könnten Sie sogar schreiben

l.^2
Dario
quelle
9
-1: Das stimmt eigentlich nicht. Matlab verfügt nicht über ein Typsystem, das stark genug ist, um Skalarfunktionen anzugeben. f wird mit dem Vektor aufgerufen und in Ihrem Beispiel wird eine einzelne Vektoraddition durchgeführt. Um dies zu überprüfen, profilieren Sie Ihr Codebeispiel ("Profil ein", bevor Sie den Code ausführen, und danach "Profil aus Bericht"). Sie werden sehen, dass es einen einzigen Anruf bei f gibt.
Herr Fooz
-1

Das Vektorisieren der Lösung wie in den vorherigen Antworten beschrieben ist wahrscheinlich die beste Lösung für die Geschwindigkeit. Vektorisieren ist auch sehr Matlaby und fühlt sich gut an.

Damit hat Matlab jetzt eine Map-Container-Klasse.

Siehe http://www.mathworks.com/help/matlab/map-containers.html

TallBrian
quelle
Op spricht von der Funktion höherer Ordnung, dh cellfunet al., Nicht von Hash-Tabellen oder Schlüssel-Wert-Paaren.
Ahmed Fasih