2009-04-06 22 views
8

Cách tốt nhất để chuyển đổi danh sách/bộ thành một dict trong đó khóa là giá trị riêng biệt của danh sách và giá trị là tần số của các giá trị riêng biệt này?Cách tốt nhất để chuyển danh sách từ thành tần số dict

Nói cách khác:

['a', 'b', 'b', 'a', 'b', 'c'] 
--> 
{'a': 2, 'b': 3, 'c': 1} 

(Tôi đã phải làm một cái gì đó giống như trên rất nhiều lần, là có bất cứ điều gì trong lib tiêu chuẩn nào đó cho bạn?)

EDIT:

Jacob Gabrielson chỉ ra có something coming in the standard lib cho 2,7/3,1 chi nhánh

+0

Có thể xác định ý bạn là gì nhất? Hiệu quả nhất? Số lượng mã tối thiểu? Dễ hiểu nhất? – Dana

Trả lời

14

Loại

from collections import defaultdict 
fq= defaultdict(int) 
for w in words: 
    fq[w] += 1 

Điều đó thường hoạt động tốt.

1

tôi phải chia sẻ một thú vị nhưng loại cách vô lý để làm việc đó mà tôi chỉ đến với:

>>> class myfreq(dict): 
...  def __init__(self, arr): 
...   for k in arr: 
...    self[k] = 1 
...  def __setitem__(self, k, v): 
...   dict.__setitem__(self, k, self.get(k, 0) + v) 
... 
>>> myfreq(['a', 'b', 'b', 'a', 'b', 'c']) 
{'a': 2, 'c': 1, 'b': 3} 
+0

(self.get (k) hoặc 0) có thể được viết tốt hơn như self.get (k, 0) –

2

Đây là một điều ghê tởm, nhưng:

from itertools import groupby 
dict((k, len(list(xs))) for k, xs in groupby(sorted(items))) 

tôi không thể nghĩ về một lý do nào đó sẽ chọn phương pháp này trên S.Lott, nhưng nếu ai đó chỉ ra nó, nó cũng có thể là tôi. :)

+1

điểm cho thông minh –

+0

Tôi phải nói rằng tôi chỉ nói điều này và thử nghiệm nó cho hiệu suất (Tôi đang nhìn vào đếm danh sách với hàng triệu đối tượng) và nhận ra điều này phải nhanh hơn việc lặp lại/thiết lập bản đồ băm ... Nhưng khi nó quay ra thì phải mất gấp 4 lần thời gian CPU cho các bài kiểm tra của tôi khi nó phải sắp xếp danh sách hoặc 2x khi danh sách đã được sắp xếp. Hấp dẫn. Nó là rất thông minh mặc dù. – iAdjunct

+0

Nếu bạn đang xử lý hàng triệu đối tượng, bạn nên sử dụng sắp xếp bên ngoài (hoặc giảm sắp xếp cho công cụ dữ liệu nơi dữ liệu nhập của bạn xuất phát, nếu có thể). 'Sort words.txt | uniq -c' hạt dẻ trong vỏ là khó để đánh bại. –

22

tôi thấy rằng dễ nhất để hiểu (trong khi có thể không phải là hiệu quả nhất) là cách để làm:

{i:words.count(i) for i in set(words)} 
+2

+1: Có để cho tôi một số đường cú pháp Python 3.0. –

+0

Đó là khá nóng –

+0

Python đẹp! –

7

Chỉ cần một lưu ý rằng, bắt đầu với Python 2.7/3.1, chức năng này sẽ được tích hợp vào mô-đun collections, xem this bug để biết thêm thông tin. Dưới đây là các ví dụ từ release notes:

>>> from collections import Counter 
>>> c=Counter() 
>>> for letter in 'here is a sample of english text': 
... c[letter] += 1 
... 
>>> c 
Counter({' ': 6, 'e': 5, 's': 3, 'a': 2, 'i': 2, 'h': 2, 
'l': 2, 't': 2, 'g': 1, 'f': 1, 'm': 1, 'o': 1, 'n': 1, 
'p': 1, 'r': 1, 'x': 1}) 
>>> c['e'] 
5 
>>> c['z'] 
0 
+2

trông đơn giản hơn thế, có vẻ như bạn chỉ có thể truyền chuỗi cho hàm tạo Counter và nó cho bạn –

+2

Bạn có thể chỉ cần làm 'Counter (word_list)'. –

1

tôi quyết định đi trước và kiểm tra các phiên bản đề nghị, tôi thấy collections.Counter theo đề nghị của Jacob Gabrielson là nhanh nhất, tiếp theo là phiên bản defaultdict bởi Slott.

Dưới đây là mã của tôi: từ bộ sưu tập nhập defaultdict từ bộ sưu tập nhập Counter

import random 

# using default dict 
def counter_default_dict(list): 
    count=defaultdict(int) 
    for i in list: 
     count[i]+=1 
    return count 

# using normal dict 
def counter_dict(list): 
    count={} 
    for i in list: 
     count.update({i:count.get(i,0)+1}) 
    return count 

# using count and dict 
def counter_count(list): 
    count={i:list.count(i) for i in set(list)} 
    return count 

# using count and dict 
def counter_counter(list): 
    count = Counter(list) 
    return count 

list=sorted([random.randint(0,250) for i in range(300)]) 


if __name__=='__main__': 
    from timeit import timeit 
    print("collections.Defaultdict ",timeit("counter_default_dict(list)", setup="from __main__ import counter_default_dict,list", number=1000)) 
    print("Dict",timeit("counter_dict(list)",setup="from __main__ import counter_dict,list",number=1000)) 
    print("list.count ",timeit("counter_count(list)", setup="from __main__ import counter_count,list", number=1000)) 
    print("collections.Counter.count "timeit("counter_counter(list)", setup="from __main__ import counter_counter,list", number=1000)) 

Và kết quả của tôi:

collections.Defaultdict 
0.06787874956330614 
Dict 
0.15979115872995675 
list.count 
1.199258431219126 
collections.Counter.count 
0.025896202538920665 

Đỗ cho tôi biết thế nào tôi có thể cải thiện việc phân tích.

Các vấn đề liên quan