2009-06-11 20 views
85

Sono un po 'sorpreso dal fatto che MATLAB non abbia una funzione Map, quindi ne ho hackerato uno insieme perché è qualcosa di cui non posso fare a meno. C'è una versione migliore là fuori? C'è una libreria di programmazione funzionale alquanto standard per MATLAB là fuori che mi manca?Funzione mappa in MATLAB?

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 

l'utilizzo sarebbe ad es.

map(@(x)x^2,1:10) 
+11

Lezione # 1 che va da altre lingue per Matlab: Non utilizzare per cicli, sono alcuni ordini di grandezza più lenta di una soluzione vectorized. – CookieOfFortune

+1

Che dire della ricorsione? – Dario

+15

Con l'introduzione del JIT, per i loop non prendi la penalità che hanno fatto una volta. – MatlabDoug

risposta

1

Se matlab non ha una funzione di mappa incorporata, potrebbe essere a causa di considerazioni di efficienza. Nella tua implementazione stai usando un ciclo per scorrere gli elementi della lista, che è generalmente disapprovato nel mondo MATLAB. La maggior parte delle funzioni MATLAB incorporate sono "vettorializzate", i. e. è più efficiente chiamare una funzione su un intero array, piuttosto che iterarlo su se stesso e chiamare la funzione per ogni elemento.

In altre parole, questo


a = 1:10; 
a.^2 

è molto più veloce di questa


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

assumendo la tua definizione di mappa.

+1

Penso che il suo punto non fosse che voleva che fosse necessariamente un loop, ma semplicemente da specificare come il risultato della serie di risultati dell'applicazione della funzione fornita agli elementi corrispondenti dell'array fornito. Non conosco molto MATLAB, ma sembra che Arrayfun faccia il suo lavoro. –

+1

La maggior parte delle funzioni e degli operatori Matlab incorporati lo fanno già: operano su ogni elemento della matrice di input e restituiscono una matrice corrispondente di risultati. – Dima

123

La risposta breve: la funzione built-in ARRAYFUN fa esattamente ciò che il vostro mappa funzione fa per matrici numeriche:

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

    1  4  9 16 25 36 49 64 81 100 

Ci sono altre due funzioni built-in che si comportano allo stesso modo: CELLFUN (che opera su elementi di array di celle) e STRUCTFUN (che opera su ciascun campo di una struttura).

Tuttavia, queste funzioni spesso non sono necessarie se si sfrutta la vettorizzazione, in particolare utilizzando arithmetic operators element-wise. Per l'esempio che ha dato una soluzione vettorializzare sarebbe:

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

    1  4  9 16 25 36 49 64 81 100 

Alcune operazioni funzionano automaticamente tutti gli elementi (come l'aggiunta di un valore scalare per un vettore) mentre altri operatori hanno una sintassi speciale per il funzionamento dell'elemento-saggio (denotata da un "." prima dell'operatore). Molte funzioni in MATLAB sono progettate per operare su argomenti vettoriali e matriciali usando operazioni element-wise, e quindi non richiedono funzioni di mappa.

In sintesi, qui alcuni modi diversi di quadratura ciascun elemento di un array:

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 

Naturalmente, per una semplice operazione di tale opzione # 1 è la scelta più ragionevole.

+2

Si noti che l'opzione 1 non è solo più semplice, ma anche più veloce (rispetto all'opzione 3, 2 dovrebbe essere molto simile a 1)! –

0

Non è necessario map poiché una funzione scalare che viene applicata a un elenco di valori viene applicata a ciascuno dei valori e quindi funziona in modo simile a map. Basta provare

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

f(l) 

Nel vostro caso particolare, si potrebbe anche scrivere

l.^2 
+9

-1: In realtà non è vero. Matlab non ha un sistema di tipi abbastanza potente da specificare le funzioni scalari. f viene chiamato con il vettore e nel tuo esempio viene eseguita una singola aggiunta vettoriale. Per verificare ciò, profila il tuo esempio di codice ("profilo su" prima di eseguire il codice, quindi "profilo off report" dopo di esso). Vedrai che c'è una sola chiamata a f. –

10

Oltre a vettoriale e le operazioni di elemento-saggio, c'è anche cellfun per le funzioni di mappatura oltre array di celle.Ad esempio:

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

Se 'UniformOutput' è vero (o non fornite), tenterà di concatenare i risultati in base alle dimensioni della matrice di celle, così

cellfun(@upper, {'a', 'b', 'c'}) 
ans = 
ABC 
3

Un piuttosto semplice soluzione , utilizzando vettorializzazione di Matlab sarebbe:

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 

Ora, digitando

c(b) = a 

rendimenti

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

c (b) è un riferimento ad un vettore di dimensione 5 con gli elementi C a indici fornite dal b. Ora se assegni valori a questo vettore di riferimento, i valori originali in c vengono sovrascritti, poiché c (b) contiene riferimenti ai valori in c e nessuna copia.

1

sembra che il built-in arrayfun non funziona se il risultato necessario è un array di funzione: es: mappa (@ (x) [xx^2 x^3], 1: 10)

lievi mods sotto fare questo lavoro meglio:

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 
+5

[ARRAYFUN] (http://www.mathworks.com/help/techdoc/ref/arrayfun.html) funzionerebbe per il tuo esempio, dovresti semplicemente includere gli argomenti di input '..., 'UniformOutput', false); 'per creare un output di matrice di celle contenente gli array, quindi formattare e combinarli come desiderato in una matrice non a celle. – gnovice

-1

vettorializzazione la soluzione come indicato nelle risposte precedenti è la probabilmente la soluzione migliore per la velocità. La vettorizzazione è anche molto Matlaby e si sente bene.

Con ciò detto Matlab ora ha una classe di contenitore Mappa.

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

+0

Op sta parlando della funzione di ordine superiore, ad esempio 'cellfun' et al., Non hash table o coppie di valori-chiave. –