2011-02-28 62 views
7

很多时候我发现自己会用Tally[ ]来计算出现的次数,然后,一旦我放弃了原来的列表,不得不添加(并加入)该计数器列出来自另一个列表的结果。聚合理货计数器

aggTally[listUnTallied__List:{}, 
     listUnTallied1_List, 
     listTallied_List] := 
Join[[email protected][listUnTallied, listUnTallied1], listTallied] //. 
    {a___, {x_, p_}, b___, {x_, q_}, c___} -> {a, {x, p + q}, b, c}; 

这样

当我计数配置,事件,做一些离散统计等

所以我定义了理货聚集了非常简单,但好用的功能这通常发生

l = {x, y, z}; lt = [email protected]; 
n = {x}; 
m = {x, y, t}; 

aggTally[n, {}] 
    {{x, 1}} 

aggTally[m, n, {}] 
    {{x, 2}, {y, 1}, {t, 1}} 

aggTally[m, n, lt] 
    {{x, 3}, {y, 2}, {t, 1}, {z, 1}} 

这个函数有两个问题:

:1)行为

Timing[Fold[aggTally[[email protected]#2, #1] &, {}, Range[100]];] 
    {23.656, Null} 
(* functional equivalent to *) 
Timing[s = {}; j = 1; While[j < 100, s = aggTally[[email protected], s]; j++]] 
    {23.047, Null} 

2)它不验证的最后一个参数是真正计数的列表或空(对我来说不那么重要了,虽然)

有一个简单的,优雅的,更快更有效的解决方案? (据我所知,这是太多的要求,但希望是免费的)

回答

9

也许,这将适合您的需求?

aggTallyAlt[listUnTallied__List : {}, listUnTallied1_List, listTallied : {{_, _Integer} ...}] := 
{#[[1, 1]], [email protected]#[[All, 2]]} & /@ 
     GatherBy[Join[[email protected][listUnTallied, listUnTallied1], listTallied], First] 

时间要好得多,并且对最后一个arg有一个基于模式的检查。

编辑:

这里是一个更快的版本:

aggTallyAlt1[listUnTallied__List : {}, listUnTallied1_List, listTallied : {{_, _Integer} ...}] := 
Transpose[{#[[All, 1, 1]], Total[#[[All, All, 2]], {2}]}] &@ 
    GatherBy[Join[[email protected][listUnTallied, listUnTallied1], listTallied], First] 

它的时序:

In[39]:= Timing[Fold[aggTallyAlt1[[email protected]#2, #1] &, {}, Range[100]];] 
Timing[s = {}; j = 1; While[j < 100, s = aggTallyAlt1[[email protected], s]; j++]] 

Out[39]= {0.015, Null} 

Out[40]= {0.016, Null} 
+0

真的很苍蝇! – 2011-02-28 15:51:03

+0

你的第二个版本非常快。看起来性能问题时,应该非常小心地使用ReplaceRepeated []。 – 2011-02-28 16:02:16

+1

事实上,'ReplaceRepeated'应该小心使用。在我的书中有关于这个主题的小节:http://www.mathprogramming-intro.org/book/node355.html。若要查看其性能相当不错的示例(由于使用链接列表),您可能需要查看此主题:http://groups.google.com/group/comp.soft-sys.math.mathematica/msg/062e206f2372d899。所以,这一切都取决于模式。与ReplaceRepeated一起使用时,具有许多空白的模式通常效率低下。 – 2011-02-28 16:10:56

2

如果你留下纯粹的象征,你可以沿着

(Plus @@ Times @@@ Join[#1, #2] /. Plus -> List /. Times -> List) & 

加盟理货清单线试一下。这很快,但返回的东西不是一个理货清单,所以它需要一些工作(在此之后它可能不再那么快了))。

编辑:所以,我已经有了一个工作版本:

aggT = Replace[(Plus @@ Times @@@ Join[#1, #2] 
        /. Plus -> List 
        /. Times[a_, b_] :> List[b, a]), 
       k_Symbol -> List[k, 1], {1}] &; 

使用一对夫妇随机的符号表,我得到

a := [email protected]; 
b := Table[f[[email protected] + 1], {i, 100}]; 

Timing[Fold[aggT[#1, #2] &, a, Table[a, {i, 100}]];] 
--> {0.104954, Null} 

该版本只增加理货清单,不检查什么,仍然返回一些整数,并与狮子座的功能相比:

Timing[Fold[aggTallyAlt1[#2, #1] &, a, Table[b, {i, 100}]];] 
--> {0.087039, Null} 

它已经是几秒钟了sl ower :-(。

噢,好的尝试。

+0

它似乎返回不均匀的元素。只有一次出现的人不会显示柜台。 – 2011-02-28 15:43:39

+0

呃,好吧,就像我说的那样,它的边缘很粗糙。主要是我只想炫耀一个盒子的想法。我会看看我是否有时间再玩一次,尽管列昂尼德看起来很棒。 – Timo 2011-02-28 17:42:43

+0

谢谢你的努力!已经有非常好的答案。无论如何,我会保持开放几天。 – 2011-02-28 21:24:36

4

这里是最快的事我已经拿出的是,(AB)使用可用于SowReap的标记:

aggTally5[untallied___List, tallied_List: {}] := 
    Last[Reap[ 
    Scan[((Sow[#2, #] &) @@@ Tally[#]) &, {untallied}]; 
    Sow[#2, #] & @@@ tallied; 
    , _, {#, Total[#2]} &]] 

不会赢得任何选美比赛,但这都是关于速度的,对吧? =)

+1

谢谢!我没有检查为什么,但似乎与** aggTally2 [m,n,lt] **(问题中的参数)失败。你去哪儿了?我们想你! :) – 2011-02-28 15:56:23

+0

非常非常忙,所以我一直潜伏着。我看到我的几个同事正在带着令人钦佩的火炬!我用正确的粘贴更新了我的答案,但是我意识到它不是很正确...... – 2011-02-28 16:18:46

+0

更新了一个可行的解决方案,并且更快地启动。 – 2011-02-28 16:50:06

5

以下解决方案只是对原始功能的小修改。它使用ReplaceRepeated之前应用Sort,因此可以使用较普遍替换模式,这使得它更快:

aggTally[listUnTallied__List : {}, listUnTallied1_List, 
    listTallied : {{_, _Integer} ...}] := 
    Sort[Join[[email protected][listUnTallied, listUnTallied1], 
    listTallied]] //. {a___, {x_, p_}, {x_, q_}, c___} -> {a, {x, p + q}, c}; 
+0

虽然性能与没有模式的解决方案没有可比性,但对于我的功能的改进真的令人印象深刻,只需稍作修改即可。谢谢。 – 2011-02-28 16:52:48