2013-10-08 46 views
3

我有一個列表。它相當大。它有超過100萬條目。我想計算每個字符串的頻率。它存儲爲字符串從1到1000我已經使用下列但它一直運行小時數:計數列表中的字符串或浮點數的頻率

d = {b:a.count(b) for b in a} 
n, m = d.keys(), d.values() 
print n, m 
+1

問題在於,爲了構建'dict',你正在做'n'次(列表長度'a'),一個操作cost'n'('a.count(b)'必須遍歷所有'a'來搜索'b's)。這意味着構建它需要花費與「n^2」成比例的時間。如果你有100萬份條目的列表,你必須對「(10^6)^ 2 = 10^12」操作進行處理。即使單個操作是機器指令,它也需要10^3秒的時間來構建它。實際上,每次操作可能需要一些(或至少)數十個機器指令,因此您必須等待幾個小時/天。 – Bakuriu

回答

5

使用collections.Counter代替:

from collections import Counter 
d = Counter(a) 

n, m = d.keys(), d.values() 
print n, m 
0

它是緩慢的,因爲你正在運行一個。計算每個字符串!

l = ['a', 'b', 'a'] 

然後str.count將被稱爲上 'A' 的兩倍,並且1次的 'B'。

當然,在「A」的結果在詞典中的第二次只是重寫,所以你甚至不從發現它

使用默認的字典,而不是

from collections import defaultdict 
d = defaultdict(int) 
for obj in your_list: 
    d[obj] += 1 

,或者再次集合模塊,計數器http://docs.python.org/2/library/collections.html#counter-objects

0

我認爲在這種情況下使用字典要容易得多。 插入字典的速度非常快,並且從字典中檢索的速度也一樣快。

下面是正是這麼做的一個示例程序:

import datetime 
import random 
def create_string(choice, size): 
    str = '' 
    for i in range(size): 
     str = str + random.choice(choice) 
    return str 

def count_all(strings): 
    count_dict = {} 
    for i in strings: 
     if i not in count_dict: 
      count_dict[i] = 1 
     else: 
      count_dict[i] = count_dict[i] + 1 
    return count_dict 

if __name__ == '__main__': 
    all_strings = [] 
    for i in range(1000000): 
     all_strings.append(create_string(['a','b','c'], 4)) 

    start = datetime.datetime.now() 
    c_dict = count_all(all_strings) 
    end = datetime.datetime.now() 
    print 'Took:', end - start 
    print 'The count of aacc is ', c_dict['aacc'] 

,它是如何公平?

./speed_test.py 
Took: 0:00:00.219815 
The count of aacc is 12317 

一點都不差,嘿? 作爲替代選項,要解決Ant提到的問題,您希望在執行計數時擺脫重複項。我們可以使用一組:

d = {b:a.count(b) for b in set(a)} 

根據我的測試,這不像字典方法一樣快,但不到一秒就足夠好。

+1

不要使用'datetime'來描述表演。使用'timeit'模塊(可能會使用iPython),因爲它將平均花費時間。如果你想使用'time.perf_counter'完成一次性基準測試,如果你使用python3.3 +,那就是它的目的。 – Bakuriu

+0

對不起,我最初使用timeit,但由於它的設置和代碼以字符串形式傳遞,我認爲這會造成一個不必要的複雜例子。 – Avatar33