使用Mathematica正确收集/收集

时间:2011-08-07 17:42:33

标签: wolfram-mathematica

如何使用Mathematica的Gather / Collect / Transpose函数进行转换:

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

{ {1, foo1, bar1}, {2, foo2, bar2}, {3, foo3, bar3} } 
编辑:谢谢!我希望有一个简单的方法,但我猜不是!

7 个答案:

答案 0 :(得分:8)

也许更容易:

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

答案 1 :(得分:7)

以下是您的清单:

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

这是一种方式:

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

修改

这是一个完全不同的版本,只是为了好玩:

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

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

编辑2

这是另一种方法,使用链接列表和内部函数来累积结果:

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

编辑3

好的,对于那些认为上述所有内容过于复杂的人来说,这是一个非常简单的基于规则的解决方案:

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

答案 2 :(得分:6)

<强> MapThread

如果保证“foo”和“bar”子列表彼此对齐(如示例中所示),并且您将考虑使用Gather / Collect /以外的函数/ Transpose,然后MapThread就足够了:

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

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

结果:

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

模式匹配

如果列表对齐,您也可以使用直接模式匹配和替换(尽管我不建议将此方法用于大型列表):

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

<强>母猪/粒

针对未对齐列表的更有效方法是使用SowReap

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

答案 3 :(得分:5)

以下是我使用What is in your Mathematica tool bag?

中发布的SelectEquivalents版本的方法
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]&)
]

这种方法非常通用。我曾经使用像GatherBy这样的函数来处理我在Monte-Carlo模拟中生成的巨大列表。现在使用SelectEquivalents进行此类操作的实现更加直观。此外,它基于Reap和Sow的组合,这在Mathematica中非常快。

答案 4 :(得分:4)

也只是为了好玩......

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

,其中

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

编辑。

更有趣......

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

答案 5 :(得分:3)

可能有点过于复杂,但是:

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

以下是其工作原理:

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

按照播放顺序返回每个列表项的唯一第一个元素(因为DeleteDuplicates从不重新排序元素)。然后,

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

利用Reap返回在不同列表中使用差异标记播放的表达式的事实。然后将它们放在一起,并进行转置。

这样做的缺点是我们扫描了两次。

编辑:

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

(非常)稍微快一点,但更不易读......

答案 6 :(得分:3)

在更新问题以使其更加明确和具体之前,我将假设我想要的内容并建议:

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

请参阅:UnsortedUnion