[PY3]——字典排序問題總結—(zip()函式、OrderedDict、itemgetter函式)

Jelly_lyj發表於2017-03-18

問題

怎樣在資料字典中執行一些計算操作(從而實現求最小值、最大值或排序等等)?

如何能根據某個或某幾個字典欄位來排序一個字典列表?

如何建立一個字典,並且在迭代或序列化這個字典的時候能夠控制元素的順序?

 

解決方案

zip( )函式

operator模組的itemgetter函式

OrderedDict 有序字典

 

zip( )

1. 為了對字典值執行計算操作,通常需要使用zip( )函式先將鍵和值反轉過來

2. 從而我們能將zip和sorted( )、max( )、min( )函式結合使用,來實現排列字典資料

prices = {
    'ACME': 37.20,
    'AAPL': 612.78,
    'IBM': 205.55,
    'HPQ': 37.20,
    'FB': 10.75
}

print(min(prices),max(prices))  #直接對字典執行普通的數學運算,其只會對key操作
AAPL IBM

print(min(prices.values()),max(prices.values())) #可通過字典的values函式解決,但輸出時只能看到values 
10.75 612.78

print(min(prices,key=lambda x:prices[x])) #可通過min/max的key屬性函式解決,但輸出同樣不好看 
FB

print(min(zip(prices.values(),prices.keys())))    #先通過zip()將字典”反轉”為(value,key)的元組序列 
(10.75, 'FB')

print(sorted(zip(prices.values(),prices.keys())))   #若恰巧出現values相同的情況,則根據key的排序結果返回  
[(10.75, 'FB'), (37.2, 'ACME'), (37.2, 'HPQ'), (205.55, 'IBM'), (612.78, 'AAPL')]

3. 執行這些計算的時候,需要注意的是zip( )函式建立的是一個只能訪問一次的迭代器

prices_and_names=zip(prices.values(),prices.keys())

print(max(prices_and_names))
(612.78, 'AAPL')

print(max(prices_and_names))   #第二次再用就報錯了
ValueError: max() arg is an empty sequence

 

operator模組的itemgetter函式

1. sorted(rows,key=itemgetter)

from operator import itemgetter
rows = [
    {'fname': 'Brian', 'lname': 'Jones', 'uid': 1003},
    {'fname': 'David', 'lname': 'Beazley', 'uid': 1002},
    {'fname': 'John', 'lname': 'Cleese', 'uid': 1001},
    {'fname': 'Big', 'lname': 'Jones', 'uid': 1004}
]

#根據任意的字典欄位key來排序
rows_by_uid=sorted(rows,key=itemgetter('uid'))
print(rows_by_uid)
[{'uid': 1001, 'lname': 'Cleese', 'fname': 'John'}, {'uid': 1002, 'lname': 'Beazley', 'fname': 'David'}, {'uid': 1003, 'lname': 'Jones', 'fname': 'Brian'}, {'uid': 1004, 'lname': 'Jones', 'fname': 'Big'}]

#也支援多個 keys
rows_by_lfname = sorted(rows, key=itemgetter('lname','fname'))
print(rows_by_lfname)
[{'uid': 1002, 'lname': 'Beazley', 'fname': 'David'}, {'uid': 1001, 'lname': 'Cleese', 'fname': 'John'}, {'uid': 1004, 'lname': 'Jones', 'fname': 'Big'}, {'uid': 1003, 'lname': 'Jones', 'fname': 'Brian'}]

#應當注意,以上兩個排序語句等價於:
rows_by_fname = sorted(rows, key=lambda r: r['uid'])
rows_by_lfname = sorted(rows, key=lambda r: (r['lname'],r['fname']))
#但使用 itemgetter() 方式會執行的稍微快點

2. itemgetter同樣適用於min( )和max( )等函式

rows_min_uid=min(rows, key=itemgetter('uid'))
print(rows_min_uid)
{'uid': 1001, 'lname': 'Cleese', 'fname': 'John'}

 

OrderedDict 有序字典

1. 為了能控制一個字典中元素的順序,你可以使用 collections 模組中的 OrderedDict 類。 在迭代操作的時候它會保持元素被插入時的順序

from collections import OrderedDict

d={}
d[0]=3;d[6]=1;d[3]=1    //仔細看插入順序
for k,v in d.items():
    print(k,v)          //輸出的時候dict字典會按照key順序來排序
0 3
3 1
6 1

od=OrderedDict()
od[0]=3;od[6]=1;od[3]=1   //但同樣的插入順序下
for k,v in od.items():
    print(k,v)            //OrdereDict會保持插入順序
0 3
6 1
3 1

2. 需要注意的是,一個 OrderedDict 的大小是一個普通字典的兩倍,因為它內部維護著另外一個連結串列,要注意記憶體消耗問題

相關文章