2013-02-12 59 views
0

首先我想道歉,如果這個問題已被問到。很難找到沒有找到如何計算散列引用數組的答案如何提高我的域名計數算法的效率?

我的函數接收來自DBI查詢的輸出,這是一個包含電子郵件地址的散列引用數組。其任務是通過他們的域名每天保持電子郵件地址。我所做的是構建域的散列到計數。問題在於陣列預計至少會存儲10,000,000封電子郵件。腳本花了幾分鐘跑完。

問題是,你能想出一種簡化算法的方法嗎?

my ($data) = shift; 
my %elements = (); 

foreach my $row (@$data) 
{ 
    my ($username, $domain) = split(/@/, $row->{addr}); 
    if (exists($elements{$domain})) 
    { 
     $elements{$domain}++; 
    } 
    else 
    { 
     $elements{$domain} = 1; 
    } 

} 

順便說一句,我對我的英語很抱歉,但我不是母語的人。謝謝。

+1

您可以添加一個域表並添加域/增加計數器時(使用觸發器?)添加電子郵件,然後你只需要每天查詢該表並清除它。 – zenpoy 2013-02-12 16:51:15

+0

你需要頻繁地這樣做嗎?爲什麼不使用一些NoSQL鍵值存儲來保存地址作爲鍵和計數值呢? – snoofkin 2013-02-12 16:55:54

回答

1

你不需要if/else邏輯。當第一次嘗試增加尚未包含在哈希中的密鑰(本例中爲域)的計數時,Perl足夠聰明,可以將計數設置爲1。

輸掉,保持增量。你可能不會得到效率的巨大提高,但你會得到一點點。否則,循環就像它真正可以得到的一樣緊密。

+0

謝謝,很高興知道這個行爲 – Layo 2013-02-19 20:12:41

1

有一個優化可以使當且僅當字符串只包含一個@

(split /\@/, $string)[1] 

相當於,但比

substr $string, 1 + index $string, '@' 

效率較低性能的提高也不會那個戲劇性如果那條線不是經常執行的話,但是在我剛跑過的一個非常不科學的基準測試中,執行時間大致上減半。

另一個不同之處是行爲,如果沒有@存在 - 的split解決方案將使undef,其中stringifies爲空字符串,但index解決方案將會給最後一個字符。

可以提高效率,進一步,如果你不介意的哈希鍵領先@

substr $string, index $string, '@' 
0

你的算法已經是O(N),作爲計數算法會大約是高效要得到。您可以進行微觀優化,如消除if子句,但不會獲得任何算法改進。

+1

它僅僅是O(N)。如果你想把這個字符串的長度作爲因子,那就是O(N * L),但那會很愚蠢。 – ikegami 2013-02-12 18:24:04

+0

@ikegami我總是不確定散列插入的複雜性,所以把它建模爲log n。我可能不應該那樣做。 – darch 2013-02-12 18:26:06

+1

如果行數是行數的兩倍,則需要兩倍的時間。 – ikegami 2013-02-12 18:29:57