2012-01-06 7 views
7

pregunta simple, dieron una lista como estaCómo eliminar el extra {} cuando el mapeo de una función a una lista

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

y supongo que tienen una función definida de esta manera:

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

Y Quiero aplicar esta función a la lista, así que si escribo

Map[foo, lst] 

esto da

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

quiero que salga como

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

por lo que funciona.

¿Cuál es la mejor manera de hacerlo? Asumo que no puedo modificar el [] definición de la función foo (digo que es construir-en)

sólo 2 maneras que sé ahora son

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

(demasiado trabajo), o

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

(menos tipeo, pero es necesario transponerlo primero)

Pregunta: ¿Alguna otra forma mejor de hacer lo anterior? Miré a otro mapa y sus amigos, y no pude ver una función para hacerlo más directamente que lo que tengo.

+1

Pregunta [relacionado] (http://stackoverflow.com/q/5746717/499167): ** Aplicar lista a argumentos en Mathematica ** – tomd

Respuesta

14

Es necesario Apply en Level 1 o su forma corta, @@@

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

Una manera posible es cambiar la cabeza de cada elemento de lst de List a foo:

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

Un poco más posibilidades para elegir:

Este Es una versión más detallada de la respuesta de Yoda.Se aplica foo en el nivel 1 de la lista lst solamente (reemplaza la cabeza List con la cabeza foo):

Apply[foo, lst, {1}] 

Esto hace lo mismo, pero los mapas Apply sobre la lista lst (esencialmente la respuesta de Andrei):

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

Y esto simplemente se cambia la lista de patrones [x__] con foo [x] en el nivel 1:

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

Acaba de informar las pruebas de rendimiento desconcertantes de los métodos de ambos (@@@, @@ # & /@):

 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}} 

Estos resultados no son aleatorios, pero más o menos proporcional de muy diferentes tamaños de datos.

@@@ es aproximadamente 3-4 veces más rápido para Subtract, Divide, Power, mientras Log@@ # & /@ es 4 veces más rápido para Plus y Times dando lugar a otras preguntas, que (como se puede creer) podría estar ligeramente
despejada por el la siguiente evaluación:

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

Sólo Plus y Times tienen atributos Flat y Orderless, mientras que entre el resto solamente Power (que parece relativamente más eficiente allí) también tiene un atributo OneIdentity.

Editar

Una explicación fiable de incremento en el rendimiento observados (gracias a las declaraciones de Leonid Shifrin) debe ir a lo largo de una ruta diferente.

Por defecto hay MapCompileLength -> 100 como podemos comprobar evaluando SystemOptions["CompileOptions"]. Para restablecer autocompilation de Mapa podemos evaluar:

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

Ahora podemos probar el rendimiento relativo de los métodos de ambos mediante la evaluación una vez más nuestra H - función de las pruebas de rendimiento en los símbolos relacionados y la 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}} 

Teniendo estos resultados podemos concluir que, en general, el enfoque de Yoda (@@@) es el más eficiente, mientras que el proporcionado por Andrei es mejor en el caso de Plus y Times debido a la compilación automática de Map que permite una mejor p rendimiento de (@@ # & /@).

+3

No es tan desconcertante si recordamos que 'Map' autocompila cuando puede, y 'Apply' se puede compilar solo por 3 cabezas:' Plus', 'Times' y' List'. OTOH, '@@@' no se autocompila. Verá aumentos de eficiencia para 'Plus' y' Times' debido a la autocompilación en la construcción '@@@ & @ @', y debido a que su entrada es una gran matriz empaquetada (que permite beneficiarse de la autocompilación) –

+1

Véase también esta respuesta mío: http://stackoverflow.com/questions/6405304/memory-use-of-apply-vs-map-virtual-memory-use-and-lock-ups/6408489#6408489, y los comentarios a continuación, para más discusión de asuntos similares. –

+0

@Leonid Gracias por un enlace interesante y comentarios. De hecho, cuando evalúo mi función 'H' en' T1 = FromPackedArray [T] 'la eficiencia relativa de' Plus' y 'Times' se reduce aproximadamente por el factor 2, mientras que la otra funciona solo por unos pocos porcentajes, sin embargo' Map 'todavía es casi dos veces más rápido para' Plus' y 'Times'. La razón de este efecto es aparentemente la autocompilación. Por otro lado, las observaciones sobre Atributos de funciones relacionadas siguen siendo válidas y espero que no haya ningún tipo de malentendido. – Artes

3

Las respuestas en Apply[] en el clavo, y es lo que hay que hacer, pero lo que estaba tratando de hacer, era reemplazar una cabeza con una cabeza List[]Sequence[], es decir, debe convertirse en List[List[3,5],List[6,7]]List[Sequence[3,5],Sequence[6,7]].

cabeza secuencia es lo que, naturalmente, se mantiene si se elimina una cabeza de cualquier lista de parámetros, por lo Delete[Plus[3,5],0] y Delete[{3,5},0]Delete[List[3,5],0] y sería toda producir Sequence[3,5].

Así [email protected][#,0]&/@{{a, b}, {c, d}, {e, f}} le dará igual que [email protected]@@{{a, b}, {c, d}, {e, f}}.

Alternativamente, foo[#/.List->Sequence]&/@{{a, b}, {c, d}, {e, f}} hace lo mismo.

+1

Tengo que estar en desacuerdo con la afirmación de que quiere convertir 'List [List [...] ..]' en 'List [Sequence [...] ..]'. Más correctamente, él quiere 'List [f ...] ', es decir, quiere cambiar los encabezados de las listas internas a' f'. – rcollyer

+0

Estoy de acuerdo en que esto es lo que finalmente "quiere". Quise decirlo en cierto sentido "lo que quieres hacer para llegar es ..." ;-) Perdón por la confusión. Para llegar a 'List [f [Sequence [...]], ...]' necesitaba una forma de convertir una lista de listas en una lista de secuencias. Aplicar lo hace internamente. –

Cuestiones relacionadas