2016-02-17 60 views
2

我是Python的新手,目前正致力於解決問題以提高編程技能。我正在處理一個問題,我需要在Python中使用stable sort字典。請看以下細節:在Python中對字典值進行穩定排序

輸入:

1 2 
16 3 
11 2 
20 3 
3 5 
26 4 
7 1 
22 4 

上面的命令,我加爲兩個lists k and v

k = ['1', '16', '11', '20', '3', '26', '7', '22'] 
v = ['2', '3', '2', '3', '5', '4', '1', '4'] 

我加入這兩個列表成爲一個字典把它作爲一個鍵值對。我已使用OrderDict,因爲我想讓元素的順序與它們在輸入中的順序相同。

from collections import OrderedDict 
d = OrderedDict(zip(k, v)) 

現在,我需要以按相反的順序字典d相對於值。 (其實,我做一個穩定的排序,自sorted在Python是一個穩定的排序,我已經使用了來源:Here)對於:

s = sorted(d, key = itemgetter(1), reverse=True) 

預期輸出:

3 5 
26 4 
22 4 
16 3 
20 3 
1 2 
11 2 
7 1 

但經過我實現了上面的sorted函數,我無法獲得預期的輸出。我得到IndexError: string index out of range

有人可以告訴我我在哪裏做錯了。我的方法錯誤或流程錯誤?你能否告訴我爲什麼我無法按預期得到產出?提前致謝。任何幫助將非常感激。

回答

4

下面是做到這一點的一種方法:

>>> sorted_kv = sorted(d.items(), key=lambda (k,v):int(v), reverse=True) 
>>> OrderedDict(sorted_kv) 
OrderedDict([('3', '5'), ('26', '4'), ('22', '4'), ('16', '3'), ... 

這需要的鍵/值對從字典中,對它們進行分類,並創建所需要訂購新的有序字典。

key=參數sorted()指定要根據第二個項目的數值對這些對進行排序。

我需要調用int()的原因是您的字典將鍵和值都保留爲字符串。按照原樣排序它們將會起作用,但會生成lexicographic ordering而不是數字。

+0

感謝您的詳細解釋。我有幾個查詢 - 1.爲什麼字典將鍵和值保留爲字符串,即使所有的值都是整數。 2.只有'd'代替'd.items'有什麼區別嗎?目的是什麼。對不起,如果它聽起來很愚蠢,但我只是想更好地理解。 – Dev

+0

@Dev 1)Python是強類型的。這意味着它不會在類型之間默默轉換;你必須強制它通過鑄造。有一些地方放鬆了一些地方(例如,不同類型之間的數學運算)。即使這些字符串只包含數字字符,它們仍然是字符串,除非明確地將它們轉換爲其他字符,否則將永遠不會被視爲任何不同的東西。 2)迭代只是'd'只會給你鑰匙。 'd.items()'返回(key,value)的元組。基本上,它可以爲您節省一些額外的字典。 – eestrada

4

您忘記使用.items()(Python3)或.iteritems()(Python2)來訪問您的字典項目。

此外,您需要導入operator模塊才能使用itemgetter()

因此,代碼看起來像:

import operator 
from collections import OrderedDict 

k = ['1', '16', '11', '20', '3', '26', '7', '22'] 
v = ['2', '3', '2', '3', '5', '4', '1', '4'] 

d = OrderedDict(zip(k, v)) 

out = sorted(d.items(), key=operator.itemgetter(1), reverse=True) 

位置列表out是這樣的:

[('3', '5'), ('26', '4'), ('22', '4'), ('16', '3'), ('20', '3'), ('1', '2'), ('11', '2'), ('7', '1')] 

爲了打印您可以通過使用訪問列表中的每個元組:

for i,k in out: 
    print(i,k) 

它給出了所需的輸出:

3 5 
26 4 
22 4 
16 3 
20 3 
1 2 
11 2 
7 1 

我已經寫了一個上面給出的代碼的例子,可以在ideone.com找到。

+0

謝謝你,我確實嘗試了,而我正在驗證'但我得到了'字符串索引超出範圍錯誤:(。和輸出你給的不是預期的輸出。我給了導入運算符 – Dev

+0

輸出如果你想打印它,你只需要訪問列表中的每一個元組,請看我更新的答案 – albert

+0

謝謝,它的工作,對不起,因爲沒有讓你更早。請告訴我,如果我不使用'd.items()'並給出'd',會發生什麼情況?它是否會迭代元素? – Dev

1

這是另一種方式來做到這一點:

from collections import OrderedDict 

k = ['1', '16', '11', '20', '3', '26', '7', '22'] 
v = ['2', '3', '2', '3', '5', '4', '1', '4'] 

d = OrderedDict(zip([int(x) for x in k], [int(y) for y in v])) # convert from string to int 
sorted_items = sorted(d.items()) 
sorted_items.reverse() 
s = OrderedDict(sorted_items) # new sorted ordered dict 
0

這是我對這項工作的想法勺:

k = ['1', '16', '11', '20', '3', '26', '7', '22'] 
v = ['2', '3', '2', '3', '5', '4', '1', '4'] 

# create a dictionary 
d = dict([(k[ind], v[ind]) for ind in range(0, len(k))]) 

for order in sorted(d, key=d.__getitem__, reverse=True): 
    print ("{}: {}".format(order, d[order])) 

輸出:

3: 5 
26: 4 
22: 4 
16: 3 
20: 3 
11: 2 
1: 2 
7: 1 

但是我注意到,那在你的預期產出'1'在'11之前。這是有原因的嗎?

相關問題