2009-12-16 60 views
14

Tôi có một collection.defaultdict (int) mà tôi đang tạo để đếm số lần một khóa hiển thị trong một tập hợp dữ liệu. Sau đó tôi muốn có thể sắp xếp nó (rõ ràng bằng cách biến nó thành danh sách đầu tiên) theo kiểu giảm dần, được đặt hàng với giá trị cao nhất trước tiên. Tôi tạo ra từ điển của tôi như sau:python, chuyển từ điển sang danh sách được sắp xếp theo giá trị thay vì khóa

adict = defaultdict(int) 

sau này tôi làm một loạt các:

adict['someval'] += 1 
adict['anotherval'] +=1 
adict['someval'] += 1 

Lý tưởng nhất là sau đó tôi muốn để có được một bản in ra:

someval => 2 
anotherval => 1 

Trả lời

35

phím A của dict, ngược-sắp xếp theo các giá trị tương ứng, tốt nhất có thể được nhận như

sorted(adict, key=adict.get, reverse=True) 

kể từ khi bạn muốn có chìa khóa/cặp giá trị, bạn có thể làm việc trên các mục như tất cả các câu trả lời khác được đề xuất, hoặc (để sử dụng phương thức ràng buộc adict.get bị ràng buộc thay vì mục công cụ hoặc lambdas lạ ;-),

[(k, adict[k]) for k in sorted(adict, key=adict.get, reverse=True)] 

Sửa: về hiệu suất, không có nhiều vào nó một trong hai cách:

$ python -mtimeit -s'adict=dict((x,x**2) for x in range(-5,6))' '[(k, adict[k]) for k in sorted(adict, key=adict.get, reverse=True)]' 
100000 loops, best of 3: 10.8 usec per loop 
$ python -mtimeit -s'adict=dict((x,x**2) for x in range(-5,6)); from operator import itemgetter' 'sorted(adict.iteritems(), key=itemgetter(1), reverse=True)' 
100000 loops, best of 3: 9.66 usec per loop 
$ python -mtimeit -s'adict=dict((x,x**2) for x in range(-5,6))' 'sorted(adict.iteritems(), key=lambda (k,v): v, reverse=True)' 
100000 loops, best of 3: 11.5 usec per loop 

Vì vậy, giải pháp dựa trên .get là giữa chừng smack ở hiệu suất giữa hai items - dựa trên cơ sở - hơi chậm hơn itemgetter, nhanh hơn một chút so với lambda. Trong các trường hợp "nút cổ chai", trong đó các phân số micro giây là rất quan trọng đối với bạn, bằng mọi cách hãy tập trung vào điều đó. Trong những trường hợp bình thường, khi thao tác này chỉ là một bước trong một số nhiệm vụ lớn hơn và ít hơn một phần nghìn giây, thì việc tập trung vào sự đơn giản của thành ngữ get là một lựa chọn hợp lý.

+3

Biến thể 'adict.get' thực hiện tra cứu chính hai lần cho từng mục chính tả. '[(k, v) cho k, v trong sắp xếp (adict.iteritems(), key = itemgetter (1), reverse = True)]' thực hiện một lần. – jfs

+0

Nếu bạn muốn các khóa có cùng giá trị được sắp xếp, có điều gì tốt hơn một "lambda khủng khiếp" không? – tgray

+1

@ J.F. Sebastian: cho rằng vấn đề, bạn có thể thả các công cụ hiểu danh sách và chỉ sử dụng: 'sắp xếp (adict.iteritems(), key = itemgetter (1), reverse = True)'. Giống như Nadia. – hughdbrown

3

Chỉ cần sắp xếp giá trị kết quả theo giá trị:

for k, v in sorted(adict.items(), key=lambda kv: kv[1], reverse=True): 
    print("%s => %s" % (k,v)) 
2
from collections import defaultdict 
adict = defaultdict(int) 

adict['a'] += 1 
adict['b'] += 3 
adict['c'] += 5 
adict['d'] += 2 

for key, value in sorted(adict.items(), lambda a, b: cmp(a[1], b[1]), reverse=True): 
    print "%r => %r" % (key, value) 

>>> 
'c' => 5 
'b' => 3 
'd' => 2 
'a' => 1 

 

41

Để điển sắp xếp:

from operator import itemgetter 

sorted(adict.iteritems(), key=itemgetter(1), reverse=True) 
0

"Đảo ngược" từ điển.

from collections import defaultdict 
inv_dict = defaultdict(list) 
for key, value in adict: 
    inv_dict[value].append(key) 
max_value= max(inv_dict.keys()) 

Tập hợp các phím với sự xuất hiện tối đa -

inv_dict[max_value] 

Tập hợp các phím theo thứ tự giảm dần do xảy ra -

for value, key_list in sorted(inv_dict): 
    print key_list, value 
2

Nếu bạn đang sử dụng python mới nhất 2.7 alpha, sau đó bạn có thể sử dụng lớp Counter trong mô-đun bộ sưu tập:

c = Counter() 

c['someval'] += 1 
c['anotherval'] += 1 
c['someval'] += 1 

print c.most_common() 

in theo đúng thứ tự:

[('someval', 2), ('anotherval', 1)] 

Mã được sử dụng trên 2,7 là available already và có một phiên bản adapted to 2.5. Có lẽ bạn muốn sử dụng nó để tiếp tục tương thích với phiên bản stdlib bản địa sắp được phát hành.

2

Lưu ý: Tôi đặt câu trả lời này như một câu trả lời để nó được nhìn thấy. Tôi không muốn upvotes. Nếu bạn muốn upvote bất cứ ai, upvote Nadia.

Các kết quả hiện trả lời chấp nhận đưa ra thời gian mà là dựa trên một trivially nhỏ dữ liệu (kích thước == 6 - (-5) == 11). Sự khác biệt về chi phí của các phương pháp khác nhau được che khuất bởi chi phí. Một trường hợp sử dụng như những từ thường xuyên nhất trong một văn bản hoặc tên thường xuyên nhất trong một danh sách thành viên hoặc điều tra dân số liên quan đến bộ dữ liệu lớn hơn nhiều.

Lặp đi lặp lại thí nghiệm với phạm vi (-n, n + 1) (Windows hộp, Python 2.6.4, mọi thời điểm trong micro):

n = 5: 11,5, 9,34, 11,3
n = 50 : 65.5, 46.2, 68.1
n = 500: 612, 423, 614

Kết quả này KHÔNG khác biệt "hơi".Câu trả lời itemgetter là người chiến thắng rõ ràng về tốc độ.

Cũng có đề cập đến "tính đơn giản của thành phần get". Đưa chúng gần nhau để dễ so sánh:

[(k, adict[k]) for k in sorted(adict, key=adict.get, reverse=True)] sorted(adict.iteritems(), key=itemgetter(1), reverse=True)

Các get thành ngữ không chỉ nhìn lên dict hai lần (như JF Sebastian đã chỉ ra), nó làm cho một danh sách (kết quả của sorted()) sau đó lặp trong danh sách đó để tạo danh sách kết quả. Tôi muốn gọi là baroque, không đơn giản. YMMV.

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