2010-03-06 33 views
26

Tôi có một danh sách có các mục lặp lại và tôi muốn danh sách các mục duy nhất có tần suất của chúng. Ví dụ: Tôi có ['a', 'a', 'b', 'b', 'b'] và tôi muốn [('a', 2), ('b', 3) ]Cách nhận các giá trị duy nhất với số lần xuất hiện tương ứng từ danh sách bằng Python?

Tìm kiếm một cách đơn giản để thực hiện việc này mà không cần lặp lại hai lần.

+1

Chỉ cần để bạn biết .. câu trả lời bạn chấp nhận vi phạm "khuyết điểm" không lặp traint. (Tôi nhận xét ở đây để bạn được thông báo :-). – Tom

+0

Tôi đồng ý. Cảm ơn, Tom. –

+0

Bạn có thể làm rõ câu hỏi của mình một chút không? Các mục của bạn luôn được nhóm lại với nhau chưa? Hoặc chúng có thể xuất hiện theo bất kỳ thứ tự nào trong danh sách không? – Tom

Trả lời

10

Nếu mục của bạn được nhóm (tức là các mặt hàng tương tự đến với nhau trong một bó), phương pháp hiệu quả nhất để sử dụng là itertools.groupby:

>>> [(g[0], len(list(g[1]))) for g in itertools.groupby(['a', 'a', 'b', 'b', 'b'])] 
[('a', 2), ('b', 3)] 
+0

@Tom: Tôi biết về giới hạn này. Khi các mục được nhóm lại, tuy nhiên, 'groupby' là cách tiếp cận hiệu quả và ưa thích –

+1

Bạn nên làm rõ điều đó ... chú ý đến ràng buộc trong câu hỏi" Tôi có một danh sách có các mục lặp lại "... danh sách OP đưa ra chỉ là một ví dụ. Tôi không nghĩ rằng giải pháp này là đủ chung. Nếu OP quy định rằng danh sách đầu vào luôn có các phần tử được nhóm lại, tôi sẽ đồng ý. – Tom

+0

@Tom: bạn nói đúng - Tôi đã cập nhật câu trả lời (BTW tôi giả định từ "các mục lặp lại" của mình mà chúng được nhóm lại) –

54

Khi Python 2.7 đi ra bạn có thể sử dụng nó collections.Counter class

nếu không thì thấy counter receipe

Dưới Python 2.7a3

from collections import Counter 
input = ['a', 'a', 'b', 'b', 'b'] 
c = Counter(input) 

print(c.items()) 

ra là

[('a', 2), ('b', 3)]

+0

Hey, mặc dù python 2.7 không hỗ trợ OP ngay bây giờ ... +1! Lớp collections.Counter rất thú vị và có vẻ như là một cách viết tắt tốt cho giải pháp mà tôi đã cung cấp. (Nó cũng có một số tính năng bổ sung thú vị). Câu trả lời này chắc chắn là câu trả lời mà mọi người sẽ muốn đọc trong tương lai. Bạn nên cập nhật với một ví dụ về cách sử dụng. – Tom

2

Tôi biết đây không phải là một lớp lót ... nhưng với tôi tôi thích nó vì nó là rõ ràng với tôi rằng chúng ta vượt qua danh sách ban đầu của các giá trị một lần (thay vì gọi đếm trên đó):

>>> from collections import defaultdict 
>>> l = ['a', 'a', 'b', 'b', 'b'] 
>>> d = defaultdict(int) 
>>> for i in l: 
... d[i] += 1 
... 
>>> d 
defaultdict(<type 'int'>, {'a': 2, 'b': 3}) 
>>> list(d.iteritems()) 
[('a', 2), ('b', 3)] 
>>> 
1

Một cách khác để làm điều này sẽ được

mylist = [1, 1, 2, 3, 3, 3, 4, 4, 4, 4] 
mydict = {} 
for i in mylist: 
    if i in mydict: mydict[i] += 1 
    else: mydict[i] = 1 

sau đó để có được danh sách các hàng,

mytups = [(i, mydict[i]) for i in mydict] 

này chỉ đi qua danh sách một lần, nhưng nó phải đi qua từ điển một lần là tốt. Tuy nhiên, cho rằng có rất nhiều bản sao trong danh sách, sau đó từ điển nên nhỏ hơn rất nhiều, do đó nhanh hơn để đi qua.

Tuy nhiên, không phải là một đoạn mã rất hay ngắn gọn, tôi sẽ thừa nhận.

+0

Điều này giống với tinh thần đối với giải pháp của tôi ... ngoại trừ defaultdict hợp nhất phần đầu tiên (vì bạn không phải kiểm tra sự tồn tại) và danh sách (mydict.iteritems()) ngắn hơn danh sách hiểu. – Tom

+0

'mytups = mydict.items()' là một cách đơn giản hơn để lấy danh sách các bộ dữ liệu. – PaulMcG

+0

Cảm ơn @Paul và @Tom. Có vẻ như luôn luôn có cách tốt hơn để làm điều gì đó bằng Python. :) – Aaron

3

"trường học cũ".

>>> alist=['a', 'a', 'b', 'b', 'b'] 
>>> d={} 
>>> for i in alist: 
... if not d.has_key(i): d[i]=1 #also: if not i in d 
... else: d[i]+=1 
... 
>>> d 
{'a': 2, 'b': 3} 
10
>>> mylist=['a', 'a', 'b', 'b', 'b'] 
>>> [ (i,mylist.count(i)) for i in set(mylist) ] 
[('a', 2), ('b', 3)] 
1

Một giải pháp mà không băm:

def lcount(lst): 
    return reduce(lambda a, b: a[0:-1] + [(a[-1][0], a[-1][1]+1)] if a and b == a[-1][0] else a + [(b, 1)], lst, []) 

>>> lcount([]) 
[] 
>>> lcount(['a']) 
[('a', 1)] 
>>> lcount(['a', 'a', 'a', 'b', 'b']) 
[('a', 3), ('b', 2)] 
1

Chuyển đổi bất kỳ cấu trúc dữ liệu vào một gấu trúc loạt s:

Mã sản phẩm:

for i in sort(s.value_counts().unique()): 
    print i, (s.value_counts()==i).sum() 
Các vấn đề liên quan