2011-02-28 93 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