2010-03-30 48 views
8

字符串我有一個字典詞典:如何排序具有鍵作爲數字在Python

a = {'100':12,'6':5,'88':3,'test':34, '67':7,'1':64 } 

我想解決這字典對於關鍵的,所以它看起來像:

a = {'1':64,'6':5,'67':7,'88':3, '100':12,'test':34 } 

回答

10

像其他人一樣指出,詞典有自己的訂貨和像你將一個列表,你可以不只是對它們進行排序。

有一兩件事我想補充的是,如果你只是想通過在有序字典的元素,這只是:

for k in sorted(a): 
    print k, a[k] # or whatever. 

如果你寧願有一個列表理解(每亞歷克斯):

sortedlist = [(k, a[k]) for k in sorted(a)] 

我想指出的是,亞歷克斯的使用key=int不會與你的榜樣工作,因爲你的關鍵之一是'test'。如果你真的想他非NUMERICS之前排序號碼,你就必須在cmp函數時:

def _compare_keys(x, y): 
    try: 
     x = int(x) 
    except ValueError: 
     xint = False 
    else: 
     xint = True 
    try: 
     y = int(y) 
    except ValueError: 
     if xint: 
      return -1 
     return cmp(x.lower(), y.lower()) 
     # or cmp(x, y) if you want case sensitivity. 
    else: 
     if xint: 
      return cmp(x, y) 
     return 1 

for k in sorted(a, cmp=_compare_keys): 
    print k, a[k] # or whatever. 

或者,也許你足夠了解你的鑰匙編寫一個函數,將它們轉換成字符串(或其他物體)的排序權:

# Won't work for integers with more than this many digits, or negative integers. 
MAX_DIGITS = 10 
def _keyify(x): 
    try: 
     xi = int(x) 
    except ValueError: 
     return 'S{0}'.format(x) 
    else: 
     return 'I{0:0{1}}'.format(xi, MAX_DIGITS) 

for k in sorted(a, key=_keyify): 
    print k, a[k] # or whatever. 

這將是比使用cmp功能快得多。

+0

我不太喜歡這樣的解決方案。 '_keyify'是不必要的僵化,我不認爲像其他一些解決方案一樣乾淨,你的'_compare_keys'使用'cmp',這通常是一個不好的跡象。 (對'try' /'''''try''''''''''''''''''''''''''''''''''''''''''')儘可能小的''''''''''''''''''''''格式(xi,MAX_DIGITS)'' 'else'塊。) – 2010-03-30 20:16:23

+0

不,這些解決方案沒有進行優化,它們只是作爲示例或起點。 (如果不知道實際的關鍵域是什麼,很難提出更好的解決方案。)我喜歡你的解決方案,除了它在Python 3中中斷的地方。我最初編寫了帶有兩行「try」塊的'_compare_keys',但是這是兩倍長。使用'try'塊來控制執行流程消除了對'yint'布爾值的需要。 – 2010-03-31 12:29:06

+0

我假設你的意思是使用'cmp'參數,而不是函數,是一個「不好的符號」,是的它,但它是由未完全定義的關鍵域引發的。這就是爲什麼我跟着'_keyify'解決方案。更好的辦法是爲鍵創建一個新的類,它可以接受字符串輸入並正確排序,並將其用作字典的鍵,但是我不知道ben是否對輸入字典有很大的控制。而且,是的,我忘了「其他」塊;最近C++太多了。固定。 – 2010-03-31 12:33:03

4

字典無序。你不能排序,因爲結果a是一個字典,並且字典沒有順序。

如果你想,說,名單中排序順序的關鍵字的列表,你可以使用如下代碼

>>> def my_key(dict_key): 
...  try: 
...   return int(dict_key) 
...  except ValueError: 
...   return dict_key 
... 
>>> sorted(a, key=my_key) 
['1', '6', '67', '88', '100', 'test'] 

這依賴於愚蠢的Python行爲的str實例總是比的情況下,更大int。 (該行爲在Python 3中得到了解決。)在優化設計中,您的詞典的關鍵字將是您可以比較理智的事物,並且您不會在代表數字和字符串的字符串中混用字符。

如果要按照始終排序的順序保存密鑰,則可以使用bisect模塊或實現依賴樹數據結構的映射。 bisect模塊不接受像排序內容這樣的參數,因爲這可能效率低下;如果您選擇使用bisect,則會使用裝飾使用undecorate模式,並保留一個取決於鍵函數結果的排序列表。

+0

請注意,使用平分維護排序列表需要O(n ** 2)時間。對分將找到每個項目以O(log n)時間插入的正確位置,但由於Python列表類似數組的性質,插入仍然每個項目需要O(n)個時間。 – 2010-03-30 20:11:15

+0

@Daniel Strutzbach,這取決於你的意思是「維護」;根據使用情況,您通常可以避免使用insort構建排序列表的二次方行爲。使用列表和「bisect」當然不會爲插入操作提供理想的性能。如果這些操作很重要,那麼最好使用「或實現依賴於樹數據結構的映射」。既然你已經爲我們做了這些,我提高了你的帖子,它引用了你的'sorteddict'實現。 – 2010-03-30 20:23:24

6

您不能在Python中對dict排序,因爲dict類型本質上是無序的。你可以做的是在使用內置函數sorted()使用它們之前對項目進行排序。您還需要一個輔助函數的數字和字符串鍵來區分:

def get_key(key): 
    try: 
     return int(key) 
    except ValueError: 
     return key 
a = {'100':12,'6':5,'88':3,'test':34, '67':7,'1':64 } 
print sorted(a.items(), key=lambda t: get_key(t[0])) 

但是在Python 3.1(2.7)的collections模塊包含可以用來實現你想要像下面的效果collections.OrderedDict類型:

def get_key(key): 
    try: 
     return int(key) 
    except ValueError: 
     return key 
a = {'100':12,'6':5,'88':3,'test':34, '67':7,'1':64 } 
b = collections.OrderedDict(sorted(a.items(), key=lambda t: get_key(t[0]))) 
print(b) 
+0

這不會得到OP所需的訂單。 – 2010-03-30 19:32:29

+0

嗨Mawushe, 首先讓我感謝你的建議。但是,給定的代碼仍然不能提供所需的解決方案。 – Joseph 2010-03-30 19:37:55

+0

你們兩個都是正確的紳士我已經更新了答案,按鍵排序並考慮到鍵的字符串性質。 – 2010-03-30 19:49:31

5

9年前我張貼recipe開始

字典無法排序 - 一個 映射沒有排序!

,並演示瞭如何獲取排序列表了字典的鍵和值。

在今天的Python和你的表現加暗示的規格,我建議:

import sys 

def asint(s): 
    try: return int(s), '' 
    except ValueError: return sys.maxint, s 

sortedlist = [(k, a[k]) for k in sorted(a, key=asint)] 

key=asint就是告訴sorted治療那些字符串鍵作爲整數進行排序的目的,使如'2''1''12'之間進行排序,而不是在它們之後 - 這就是你所要求的,並且所有非全數字鍵都排在所有的 之後。如果您還需要處理表示大於sys的整數的全部數字鍵字符串。MAXINT,這是一個有點棘手,但仍是可行的:

class Infinity(object): 
    def __cmp__(self, other): return 0 if self is other else 1 
infinite = Infinity() 
def asint(s): 
    try: return int(s), '' 
    except ValueError: return infinite, s 

在一般情況下,你可以,如果你從一開始就;-)更精確地指定您的具體要求得到更好的答案更快。

+0

對於指定的輸入OP,這會失敗,因爲當遇到'test''時'int'會引發'ValueError'。 – 2010-03-30 19:33:05

+0

@Mike,對 - 讓我解決這個問題。 – 2010-03-30 19:34:37

+0

嗨亞歷克斯, 謝謝你的善意幫助和建議。有效...! – Joseph 2010-03-30 19:40:26

2

如果您安裝我的blist程序包,它包含sorteddict類型。那麼你可以簡單地說:

from blist import sorteddict 

def my_key(dict_key): 
     try: 
       return int(dict_key) 
     except ValueError: 
       return dict_key 

a = {'100':12,'6':5,'88':3,'test':34, '67':7,'1':64 } 
print sorteddict(my_key, **a).keys() 

輸出:

['1', '6', '67', '88', '100', 'test'] 
+0

把7個空格縮進';)',如果你需要一個總是排序的映射,這是一個很好的解決方案。 – 2010-03-30 20:05:32