2012-01-06 4 views
7

semplice domanda, data una lista come questaCome rimuovere l'extra {} quando Mappare una funzione a una lista

Clear[a, b, c, d, e, f]; 
lst = {{a, b}, {c, d}, {e, f}}; 

e immagino che abbia una funzione definita in questo modo:

foo[x_,y_]:=Module[{},...] 

E voglio applicare questa funzione alla lista, quindi se ho tipo

Map[foo, lst] 

questo dà

{foo[{a, b}], foo[{c, d}], foo[{e, f}]} 

voglio che venga fuori come

{foo[a, b], foo[c, d], foo[e, f]} 

così funziona.

Qual è il modo migliore per farlo? Presumo che non posso modificare la [] definizione della funzione foo (dire che è build-in)

solo 2 modi che conosco ora sono

Map[foo[#[[1]], #[[2]]] &, lst] 
{foo[a, b], foo[c, d], foo[e, f]} 

(troppo lavoro), o

MapThread[foo, Transpose[lst]] 
{foo[a, b], foo[c, d], foo[e, f]} 

(meno la digitazione, ma è necessario trasporre prima)

Domanda: altri modi migliori per fare quanto sopra? Ho guardato altre mappe e i suoi amici, e non ho potuto vedere una funzione per farlo più direttamente di quello che ho.

+1

[Correlato] (http://stackoverflow.com/q/5746717/499167) domanda: ** Applica lista agli argomenti in Mathematica ** – tomd

risposta

14

È necessario Apply in Level 1 o la sua forma breve, @@@

[email protected]@@lst  
{foo[a, b], foo[c, d], foo[e, f]} 
7

Un modo possibile è quello di cambiare la testa di ogni elemento di lst da List a foo:

foo @@ # & /@ lst 
{foo[a, b], foo[c, d], foo[e, f]} 
4

Un po 'di più possibilità di scegliere da:

questa l'ho s una versione più prolissa della risposta di yoda.Si applica foo al livello 1 della lista unica lst (sostituisce la testa List con la testa foo):

Apply[foo, lst, {1}] 

Questo fa lo stesso, ma le mappe Apply oltre l'elenco lst (in sostanza la risposta di Andrei):

Map[Apply[foo, #] &, lst ] 

E questo solo sostituisce l'elenco modello [x__] con foo [x] a livello 1:

Replace[lst, List[x__] -> foo[x], 1] 
6

Giusto per segnalare test delle prestazioni sconcertanti dei metodi di entrambi (@@@, @@ # & /@):

 T = RandomReal[{1,100}, {1000000, 2}]; 

     H[F_Symbol, T_List] := 

        [email protected][F @@@ T;]/[email protected][F @@ # & /@ T;] 

     Table[{ToString[F], H[F, T]}, {F, {Plus, Subtract, Times, Divide, Power, Log}}] 

Out[3]= {{"Plus",  4.174757}, 
     {"Subtract", 0.2596154}, 
     {"Times", 3.928230}, 
     {"Divide", 0.2674164}, 
     {"Power", 0.3148629}, 
     {"Log",  0.2986936}} 

Questi risultati non sono casuali, ma grosso modo proporzionale per dimensioni molto diverse di dati.

@@@ è circa 3-4 volte più veloce per Subtract, Divide, Power, Log mentre @@ # & /@ è 4 volte più veloce per Plus e Times dando origine ad un'altra domanda, che (come si può credere) poteva essere leggermente
chiarite dalla la seguente valutazione:

[email protected]{Plus, Subtract, Times, Divide, Power, Log} 

solo Plus e Times avere attributi Flat e Orderless, mentre tra gli altri solo Power (che sembra relativamente il più efficiente lì) ha anche un attributo OneIdentity.

Modifica

Una spiegazione affidabile per un aumento delle prestazioni osservate (grazie alle osservazioni di Leonid Shifrin) dovrebbe andare lungo un percorso diverso.

Per impostazione predefinita c'è MapCompileLength -> 100 in quanto è possibile verificare la valutazione SystemOptions["CompileOptions"]. Per ripristinare autocompilation di Map possiamo valutare:

SetSystemOptions["CompileOptions" -> "MapCompileLength" -> Infinity] 

Ora possiamo testare la performance relativa dei metodi sia valutando una volta di più la nostra H - funzione di test di prestazioni su simboli correlati e lista:

  Table[{ToString[F], H[F, T]}, {F, {Plus, Subtract, Times, Divide, Power, Log}}] 

Out[15]= {{"Plus",  0.2898246}, 
      {"Subtract", 0.2979452}, 
      {"Times",  0.2721893}, 
      {"Divide", 0.3078512}, 
      {"Power",  0.3321622}, 
      {"Log",  0.3258972}} 

Con questo risultato possiamo concludere che, in generale, l'approccio di Yoda (@@@) è il più efficiente, mentre quello fornito da Andrei è migliore in caso di Plus e Times a causa della compilazione automatica di Map che consente una migliore p erformance di (@@ # & /@).

+3

Non così sconcertante se ricordiamo che 'Mappa' si compila automaticamente quando è possibile, e 'Apply' può essere compilato per soli 3 capi:' Plus', 'Times' e' List'. OTOH, '@@@' non viene compilato automaticamente. Vedete incrementi di efficienza per 'Plus' e' Times' a causa dell'autocompilazione nel costrutto '@@ # &/@', e poiché il vostro input è un grande array compresso (che consente di beneficiare dell'autocompilazione) –

+1

Vedere anche questa risposta mio: http://stackoverflow.com/questions/6405304/memory-use-of-apply-vs-map-virtual-memory-use-and-lock-ups/6408489#6408489 e i commenti sottostanti, per più discussioni su argomenti simili. –

+0

@Leonid Grazie per link e commenti interessanti. Infatti, quando valuto la mia funzione 'H' su' T1 = FromPackedArray [T] 'l'efficienza relativa di' Plus' e 'Times' rallenta più o meno del fattore 2, mentre l'altra funziona solo di poche percentuali, tuttavia' Mappa 'è ancora quasi due volte più veloce per' Plus' e 'Times'. La ragione di questo effetto è apparentemente l'autocompilazione. D'altra parte, le osservazioni sugli attributi delle funzioni correlate sono ancora valide e spero che non ci dovrebbe essere alcun tipo di incomprensione. – Artes

3

Le risposte su Apply[] sono esatte, ed è la cosa giusta da fare, ma quello che stavi cercando di fare, è stato quello di sostituire una testa List[] con una testa Sequence[], vale a dire List[List[3,5],List[6,7]] dovrebbe diventare List[Sequence[3,5],Sequence[6,7]].

testa Sequence è ciò che naturalmente rimane se un capo di una lista di parametri viene cancellato, in modo Delete[Plus[3,5],0] e Delete[{3,5},0] e Delete[List[3,5],0] sarebbero tutti produrre Sequence[3,5].

Quindi [email protected][#,0]&/@{{a, b}, {c, d}, {e, f}} ti darà lo stesso come [email protected]@@{{a, b}, {c, d}, {e, f}}.

In alternativa, foo[#/.List->Sequence]&/@{{a, b}, {c, d}, {e, f}} fa la stessa cosa.

+1

Non sono d'accordo con l'affermazione che vuole trasformare 'List [List [...] ..]' in 'List [Sequence [...] ..]'. Più correttamente, vuole 'Lista [f [...] ..]', cioè vuole cambiare le teste delle liste interne a 'f'. – rcollyer

+0

Sono d'accordo che questo è ciò che alla fine "vuole". Intendevo dire che in un certo senso "quello che vuoi fare per arrivarci è ..." ;-) Scusa per la confusione. Per arrivare a 'List [f [Sequence [...]], ...]' aveva bisogno di un modo per convertire una lista di liste in una lista di sequenze. Applica lo fa internamente. –