2011-08-07 15 views
5

¿Cómo uso Mathematica de Gather/Recoger/transporte funciones para convertir:Usando Mathematica Reunir/Recoger adecuadamente

{ { {1, foo1}, {2, foo2}, {3, foo3} }, { {1, bar1}, {2, bar2}, {3, bar3} } } 

a

{ {1, foo1, bar1}, {2, foo2, bar2}, {3, foo3, bar3} } 

EDIT: Gracias! Esperaba que hubiera una manera simple, ¡pero supongo que no!

+5

mi humilde opinión, el requisito funcional podría haber sido escrito algo mejor. Tu ejemplo deja mucho que adivinar. –

+0

Sí, actualice la pregunta para ser más específico. Actualmente es bastante ambiguo. –

+0

barrycarter, todavía estoy esperando una pregunta aclarada. –

Respuesta

7

Aquí está la lista:

tst = {{{1, foo1}, {2, foo2}, {3, foo3}}, {{1, bar1}, {2, bar2}, {3, bar3}}} 

Aquí es una manera:

In[84]:= 
Flatten/@Transpose[{#[[All,1,1]],#[[All,All,2]]}]&@ 
    GatherBy[Flatten[tst,1],First] 

Out[84]= {{1,foo1,bar1},{2,foo2,bar2},{3,foo3,bar3}} 

EDITAR

Aquí es una versión completamente diferente, sólo por diversión:

In[106]:= 
With[{flat = Flatten[tst,1]}, 
    With[{rules = Dispatch[[email protected]@@flat]}, 
     Map[{#}~Join~ReplaceList[#,rules]&,DeleteDuplicates[flat[[All,1]]]]]] 

Out[106]= {{1,foo1,bar1},{2,foo2,bar2},{3,foo3,bar3}} 

EDIT 2

Y aquí es otra manera, utilizando listas enlazadas y función interna para acumular los resultados:

In[113]:= 
Module[{f},f[x_]:={x}; 
    Apply[(f[#1] = {f[#1],#2})&,tst,{2}]; 
    Flatten/@Most[DownValues[f]][[All,2]]] 

Out[113]= {{1,foo1,bar1},{2,foo2,bar2},{3,foo3,bar3}} 

EDITAR 3

bien, para aquellos que se consideran todos de los anteriores demasiado complicados, aquí hay una solución basada en reglas muy simple:

In[149]:= 
GatherBy[Flatten[tst, 1], First] /. els : {{n_, _} ..} :> {n}~Join~els[[All, 2]] 

Out[149]= {{1, foo1, bar1}, {2, foo2, bar2}, {3, foo3, bar3}} 
+1

En la Edición 3, ¿qué quiere decir 'els:' o hacer? ¿Es una manera de nombrar el patrón que sigue? – DavidC

+0

@David Yep. http://reference.wolfram.com/mathematica/ref/Pattern.html –

+4

@David: el estándar 'x_' es en realidad abreviado para' x: _', pero el primero es tan común que muchas personas no reconocen este último. Ambos se leen "el patrón llamado' x' que coincide con 'Blank []' ". – Simon

3

Tal vez un poco demasiado complicado, pero:

lst = {{{1, foo1}, {2, foo2}, {3, foo3}}, {{1, bar1}, {2, bar2}, {3, bar3}}} 

Map[ 
    Flatten, 
    {Scan[Sow[#[[1]]] &, 
       Flatten[lst, 1]] // Reap // Last // Last // DeleteDuplicates, 
    Scan[Sow[#[[2]], #[[1]]] &, 
      Flatten[lst, 1]] // Reap // Last} // Transpose 
] 
(* 
{{1, foo1, bar1}, {2, foo2, bar2}, {3, foo3, bar3}} 
*) 

Así es como funciona esto:

Scan[Sow[#[[1]]] &, 
    Flatten[lst, 1]] // Reap // Last // Last // DeleteDuplicates 

devuelve los primeros elementos únicos de cada uno de los elementos de la lista, en el orden en que fueron sembradas (ya DeleteDuplicates Nunca reordena los elementos). Entonces,

Scan[Sow[#[[2]], #[[1]]] &, 
     Flatten[lst, 1]] // Reap // Last 

explota el hecho de que Reap devuelve expresiones sembradas con etiquetas de diferencia en las diferentes listas. Entonces, júntelos y transpórtelos.

Esto tiene la desventaja de que escaneamos dos veces.

EDIT:

Este

Map[ 
    Flatten, 
    {[email protected]#[[1]], 
      Rest[#]} &@[email protected][ 
       Scan[(Sow[#[[1]]]; Sow[#[[2]], #[[1]]];) &, 
        Flatten[lst, 1]]] // Transpose 
] 

es (muy) poco más rápido, pero es aún menos legible ...

8

Quizás más fácil:

tst = {{{1, foo1}, {2, foo2}, {3, foo3}}, {{1, bar1}, {2, bar2}, {3, bar3}}}; 

GatherBy[Flatten[tst, 1], First] /. {{k_, n_}, {k_, m_}} -> {k, n, m} 
(* 
-> {{1, foo1, bar1}, {2, foo2, bar2}, {3, foo3, bar3}} 
*) 
+0

No te vi solución hasta mi última edición. Estaba pensando en la misma línea, pero el principal problema que me llevó algún tiempo descifrar fue manejar una cantidad arbitraria de términos en las sublistas en el enfoque basado en reglas: el suyo solo maneja exactamente dos términos. –

+0

@Leonid Tienes razón, pero no estoy seguro de si se solicita dicha generalización en la pregunta –

+0

Tienes razón, puede que no sea así. –

6

MapThread

Si el "nombre" y sublistas "bar" están garantizados para estar alineados entre sí (como en el ejemplo) y si se considere el uso de funciones distintas de Gather/Collect/Transpose, entonces será suficiente MapThread:

data={{{1,foo1},{2,foo2},{3,foo3}},{{1,bar1},{2,bar2},{3,bar3}}}; 

MapThread[{#1[[1]], #1[[2]], #2[[2]]}&, data] 

resultado:

{{1, foo1, bar1}, {2, foo2, bar2}, {3, foo3, bar3}} 

coincidencia de patrón

Si las listas son no alineados, también se puede utilizar la coincidencia de patrones recta y reemplazo (aunque yo no recomendaría este enfoque para grandes listas) :

data //. 
    {{h1___, {x_, foo__}, t1___}, {h2___, {x_, bar_}, t2___}} :> 
    {{h1, {x, foo, bar}, t1}, {h2, t2}} // First 

Sow/Reap

Un enfoque más eficiente para las listas no alineados utiliza Sow y Reap:

Reap[Cases[data, {x_, y_} :> Sow[y, x], {2}], _, Prepend[#2, #1] &][[2]] 
+0

Tenía la misma idea, pero estaba usando Union en lugar de su función pura ... –

4

también sólo por diversión ...

DeleteDuplicates /@ Flatten /@ GatherBy[Flatten[list, 1], First] 

donde

list = {{{1, foo1}, {2, foo2}, {3, foo3}}, {{1, bar1}, {2, bar2}, {3, 
    bar3}}} 

Editar.

Algunos más divertido ...

Gather[#][[All, 1]] & /@ Flatten /@ GatherBy[#, First] & @ 
Flatten[list, 1] 
+0

Ese es exactamente el código que escribí ... – Simon

+0

@Simon Sí, esa es la forma más directa de hacerlo. pero, ¿dónde está la diversión en eso? :) – acl

+0

@Simon. No vi tu código. Publiqué esto justo cuando WReach publicó su respuesta. Pensé en eliminarlo pero decidí dejarlo allí ... – tomd

5

Aquí es cómo lo haría utilizando la versión de SelectEquivalents he publicado en What is in your Mathematica tool bag?

l = {{{1, foo1}, {2, foo2}, {3, foo3}}, {{1, bar1}, {2, bar2}, {3, bar3}}}; 

SelectEquivalents[ 
    l 
    , 
    MapLevel->2 
    , 
    TagElement->(#[[1]]&) 
    , 
    TransformElement->(#[[2]]&) 
    , 
    TransformResults->(Join[{#1},#2]&) 
] 

Este método es bastante genérico. Solía ​​usar funciones como GatherBy antes para tratar grandes listas que genero en las simulaciones de Monte-Carlo. Ahora con las implementaciones de SelectEquivalents para tales operaciones son mucho más intuitivas. Además, se basa en la combinación Reap and Sow, que es muy rápida en Mathematica.

3

hasta que la cuestión se actualiza para ser más claro y específico, asumiré lo que yo quiero, y sugerir esto:

UnsortedUnion @@@ #~Flatten~{2} & 

Ver: UnsortedUnion

+1

Bienvenido de nuevo mr.wizard. ¿Tuviste unas buenas vacaciones? ¿Has visto esta pregunta (http://stackoverflow.com/q/6505675/615464)? Creo que te gustará ;-) –

+0

@Sjoerd Gracias, y sí. No, no lo hice. Jaja! –

Cuestiones relacionadas