python字典集合基礎和一些經典使用案例

1. 寫在前面

藉着昨天的列表, 今天整理一些python字典和集合的基礎和一些經典使用案例, 依然是從使用的角度去整理, 關於列表的理論知識和細節知識, 這裏不做整理。

首先, 會整理字典和集合的基本操作, 字典創建的五種方法, 涉及字典的基礎操作(字典的遍歷, 字典的鍵值集合獲取, 判斷某些鍵是否在字典中, 鍵值對的添加和刪除), 然後整理學完了字典應該怎麼去用, 這個就涉及了一些經典的使用案例(topn鍵, 重複最多, 邏輯合併等), 當然也是不全, 後期根據學習再進行補充。

大綱如下

  • python字典和集合的基本操作
  • 經典使用案例

2. python字典和集合的基本操作

2.1 python字典

關於python字典的原理,這裏就不多講, 主要是怎麼用? 首先是創建字典, 這裏介紹五種常用的方法:

# 手動
dic = {'a': 1, 'b': 3, 'c': 3}

# dict()
dict(a=1, b=2, c=3)

# 鍵值對+關鍵字參數
dict({'a':1, 'b': 2}, c=3, d=4)

# 可迭代對象   
dict([('a', 1), ('b', 2)], c=3)

# fromkeys()方法
{}.fromkeys(['k1', 'k2', 'k3'], [1, 2, 3])
{'a':1}.fromkeys(['c', 'd'], [1, 2])

涉及字典的基本操作, 主要包括字典的遍歷, 字典的鍵值集合獲取, 判斷某些鍵是否在字典中, 鍵值對的添加和刪除等。

# 遍歷
d = {'a':1, 'b':2, 'c':3}
for key, value in d.items():
    print(key, value)

# 獲得所有鍵的集合
set(d)
set(d.keys())

# 獲取值的集合
set(d.values())

# 判斷鍵是否在字典中
if 'c' in d:
    print('yes')

if 'e' not in d:
    print('no')
    
# 添加修改鍵值對
d['d'] = 4
d

# 刪除鍵值對
del d['d']
d
d.pop('c')
d

# 批量更新字典  update
d.update({'c':3, 'd':4, 'e':5})
d

# 如果僅當字典中不存在某個鍵值對時,才插入到字典中, 如果存在,不必插入
a = {'a': 1, 'b': 2}
r = a.setdefault('c', 3)
a

下面是三種字典視圖:

"""字典視圖  它們都是原字典的視圖,修改原字典對象,視圖對象的值也會發生改變。"""
d = {'a': 1, 'b': 2, 'c': 3}
d.values()
d.keys()
d.items()

關於字典, 我們要注意: 可哈希的對象才能作爲字典的鍵。 這個詳情看python幕後的不爲人知(一)

2.2 python集合

集合是一種不允許元素出現重複的容器。如果判斷一個列表中是否含有重複元素,便可藉助集合這種數據類型。與字典(dict)類似,集合(set)也是由一對花括號({})創建。但是,容器內的元素不是鍵值對。同字典類似,集合內的元素必須是可哈希類型(hashable)。

"""集合創建"""
a = {1, 2, 3}
a = set([1, 3, 5, 7])

下面是關於集合的方法:

# 求並集
a = {1, 3, 5, 7}
b, c = {3, 4, 5, 6}, {6, 7, 8, 9}
d = a.union(b, c)
print(d)

# 求差集
m = a.difference(b, c)
print(m)

# 求交集
n = a.intersection(b, c)
print(n)


"""是不是子集"""
a = {1, 3, 5, 4}
b = {1, 3, 5, 7}

a.issubset(b)

上面這些都是一些常規操作,我們得掌握, 這些都是常規操作, 基於這些操作, 才能去完成一些複雜的任務。 下面的這些案例都會看到上面這些知識的身影。

3. 經典使用案例

  1. 字典並集
    這個使用就是給定兩個字典,然後返回字典的並集

    def merge(d1, d2):
    	return {**d1, **d2}
    a = {'a': 11, 'b': 12}
    b = {'a': 20, 'c': 30}
    merge(a, b)               # 同鍵的會發生覆蓋
    
    ## 結果
    {'a': 20, 'b': 12, 'c': 30}
    
  2. 求兩個字典差
    這個就是在說, 返回只出現在第一個字典裏面的鍵值對, 也是傳入兩個字典

    def difference(d1, d2):
        return dict([(k, v) for k, v in d1.items() if k not in d2])
    
    a = {'a': 11, 'b': 12}
    b = {'a': 20, 'c': 30}
    difference(a, b)  # {'b': 12}
    
  3. 按照字典的鍵值排序
    這個就是給字典進行鍵值排序, 我們知道普通的字典是不管順序的。 這裏就是用sorted函數, 然後傳入相應的比較值就可以。

    def sort_by_key(d):
    	return sorted(d.items(), key=lambda x: x[0])
    
    def sort_by_values(d):
    	return sorted(d.items(), key=lambda x: x[1])   # 可以指定reverse=True進行降序
    
    m = dict([('c', 3), ('a', 2), ('b', 1)])
    
    sort_by_key(m)      # [('a', 2), ('b', 1), ('c', 3)]
    sort_by_values(m)   # [('b', 1), ('a', 2), ('c', 3)]
    

    這個地方比較難理解的就是函數裏面的lambda那個地方, 上一篇文章中有個lambda的動畫。 這裏再結合這個例子,簡單的說一下這個過程。因爲這種lambda的形式,後面的案例還有很多次出現,所以最好弄明白內部的過程。 簡單看一下內部的圖:
    在這裏插入圖片描述
    上面這個圖就是sort_by_key這個函數的工程過程, 當然這個是最後的結果了。 下面我說一下這個過程:

    首先運行到sort_by_key這個函數, 傳進來一個字典,用d指向它。 那麼我們得想一下我們的目標是把字典按照鍵的大小進行排序, 那麼肯定我們需要遍歷字典中的每個鍵, 然後根據這個鍵的大小進行排序。 所以我們用了一個sorted函數, 第一個參數就是我們要排序的值, 傳進去了d.items(), 這個就是[(a, 3), (b, 1), (c, 2)], 我們要把這個進行排序。
    但是我們要按照什麼樣的規則排序呢? 得告訴sorted的函數, 這個就是key關鍵字, 讓sorted函數根據這個關鍵字進行字典的排序。 但是key這裏得是一個序列啊, 畢竟要排序嘛? 所以這裏就用了一個lambda函數, 這裏的x是lambda的形參, 它會依次指向字典裏面的三個元組, 後面的x[0]表示lambda函數的返回值, 1就表示[a, b, c], 這樣執行完lambda之後, key那裏就是一個序列了, 然後sorted函數基於這個序列的值把字典進行排序返回。 按值排序其實同理, 無非就是把x[0]變成了x[1], 就是要按照序列[3, 1, 2]將字典進行排序返回。

    所以key 函數一般會與 lambda 匿名函數結合使用, 而這個原理就是上面的這個過程, 有種遍歷獲得可迭代對象的每個元素,然後進行操作的感覺。 包括之前的max(lst, key=lambda v: lst.count(v))求列表裏面出現次數最多的元素, 根據上面的這個過程,這裏就一目瞭然了。 key這裏就是每個元素出現的次數, max會求出最大次數, 然後返回lst裏面對應的元素。好吧, 最後面我會拿上一次的列表例子詳細說一下這個過程。

  4. 最大鍵或者最大值
    這個就是返回字典裏面有最大鍵的那個鍵值對。或者是有最大值的鍵值對。
    最大鍵的思路就是用max函數獲取最大鍵, 然後根據最大鍵返回相應的值。

    def max_key(d):
        if len(d) == 0:
            return []
        max_key = max(d.keys())
        return (max_key, d[max_key])
    
    max_key({'a': 3, 'b': 2, 'c': 1})   # ('c', 1)
    

    最大值的思路也是求出最大值, 然後遍歷字典, 看看哪個鍵值對等於這個值, 返回。

    def max_values(d):
        if len(d) == 0:
            return []
        max_values = max(d.values())
        return [(key, max_values) for key in d if d[key]==max_values]
    
    max_values({'a': 3, 'b': 2, 'c': 1})  # [('a', 3)]
    
  5. 集合最值
    這個是找出集合裏面的最大值和最小值, 並裝到元組裏面返回。

    def set_max_min(s):
        return (max(s), min(s))
    
    set_max_min({5, 1, 2, 4})     # (5, 1)
    
  6. 更長的集合
    這個就是傳入多個集合, 返回最長的那個, 和上一次的列表最長差不多

    def long(*s):
        return max(*s, key=lambda x : len(x))
    
    long({1,3,5,7},{1,5,7})
    
  7. 重複最多
    這個就是在兩個列表中, 找出重疊次數最多的元素進行返回。 這個得先一下思路: 這個問題我是有兩個列表, 然後返回重疊次數最多的元素。也就是在兩個列表中都出現, 且出現的次數最多。 所以分爲下面三個步驟:

    • 首先, 我得先把在兩個列表中都出現的元素找出來。 這個就用到了集合和交操作
    • 其次, 我得獲得上面每個元素在兩個列表中出現的次數, 然後返回最小的次數作爲每個元素的出現次數
    • 最後, 在這些次數中, 找到最大次數對應的元素

    基於上面的分析, 我們就可以寫一個函數了:

    def overlap_max(lst1, lst2):
    	# 首先, 獲得交集
    	overlap = set(lst1).intersection(set(lst2))
    	
    	# 遍歷這個overlap, 看看在兩個列表中的出現次數, 返回最小值
    	ox = [(x, min(lst1.count(x), lst2.count(x))) for x in overlap]
    
    	# 返回這裏面的最大次數的元素
    	return max(ox, key=lambda x: x[1])
    
    max_overlap([1,2,2,2,3,3],[2,2,3,2,2,3])   # (2, 3)
    
  8. topn鍵
    這個是找字典前n個最大值,對應的鍵。

    這個我們的常規思路就是先把字典的值進行排序, 然後返回前n個最大的。 所以就來了第一版:

    def topn_dict(d, n):
    	if len(d) == 0:
    		return 
    	
    	sort_val_d = sorted(d.items(), key=lambda x: x[1])
    	return [ele[0] for ele in sort_val_d[:n]]
    
    
    topn_dict({'a': 10, 'b': 8, 'c': 9, 'd': 10}, 3)  # ['a', 'd', 'c']
    

    當然, python還有一個簡潔版, 那就是用heapq裏面的nlargest函數。這個參數,接收的第一個參數就是n, 其次是對象, 然後是key, 最後返回的是前n個最大的。 其實內部原理就是我上面的那種。 但既然有了, 我們就可以直接用。

    from heapq import nlargest
    
    def topn_dict1(d, n):
    	return nlargest(n, d, key=lambda k: d[k])
    
  9. 一鍵對多值字典
    當有一個鍵對應多個值的時候,我們如何存到字典中? 看下面例子:

    lst = [(1, 'apple'), (2, 'orange'), (1, 'compute')]
    dict(lst)   # {1: 'compute', 2: 'orange'}
    

    lst有是元組的列表, 如果想把這個存成字典的形式, 使用dict之後,變成了{1: 'compute', 2: 'orange'}, 也就是1鍵對應了兩個值, 用dict,變成字典忽略了一個。 所以想辦法自己存:直觀思路就是遍歷列表, 如果這個鍵在字典中, 那麼直接對應的k加入元素, 否則,就建一個k加入元素。 所以出來了第一個版本:

    d = {}
    for k, v in lst:
        if k not in d:
            d[k] = []
        d[k].append(v)
    d     # {1: ['apple', 'compute'], 2: ['orange']}
    

    這樣就可以了, 但是有一個if判斷,不是很優雅, 所以可以使用collections模塊中的defaultdict, 它能創建屬於某個類型的自帶初始值的字典

    from collections import defaultdict
    
    d = defaultdict(list)
    for k, v in lst:
    	d[k].append(v)
    
    d   # defaultdict(list, {1: ['apple', 'compute'], 2: ['orange']})
    
  10. 邏輯上合併字典
    這個是在邏輯上合併字典, 不重新生成字典, 改變新的字典的值原字典也會改變。 我們上面也有個合併字典, 我們拿下來看一下普通的字典合併:

    def merged(d1, d2):
        return {**d1, **d2}
    
    dic1 = {'x': 1, 'y': 2 }
    dic2 = {'y': 3, 'z': 4 }
    
    merged_dic = merged(dic1, dic2)
    merged_dic      # {'x': 1, 'y': 3, 'z': 4}
    
    merged_dic['x'] = 10
    merged_dic  # {'x': 10, 'y': 3, 'z': 4}
    
    dic1   # {'x': 1, 'y': 2}
    

    這個我們會發現, 如果是改變新的字典merged_dict的值, 發現不影響dic1。 那麼有沒有一種方法, 合併後的字典不重新建立字典呢? 只從邏輯上合併, 如果改了新字典中的值,能夠使得原來字典的值也相應變化呢? 那就是collections模塊裏面的ChainMap函數了。 它在內部創建了一個容納這些字典的列表。使用 ChainMap 合併字典, 可以實現字典邏輯上的合併。

    from collections import ChainMap
    
    mer = ChainMap(dic1, dic2)
    mer       # ChainMap({'x': 1, 'y': 2}, {'y': 3, 'z': 4})
    
    mer['x'] = 10
    mer     # ChainMap({'x': 10, 'y': 2}, {'y': 3, 'z': 4})
    
    dic1      # {'x': 10, 'y': 2}
    

    可以發現, 這個就實現了字典的邏輯合併。

上面就是python字典的基礎和經典使用案例了。

下面藉着這個機會再補充一個例子, 因爲上面的某些案例中用到了key函數與lambda進行結合。 我們看看究竟內部這個函數在怎麼樣工作:
看一個返回最長列表的例子(和上面最大長度的集合的例子一樣):

def max_len(*lists):
	return max(*lists, key=lambda v: len(v))

r = max_len([1, 2, 3], [4, 5, 6, 7], [8])
r # [4, 5, 6, 7]

在這裏詳細說一下lambda函數。

首先, 把下面的三個列表傳入到max_len函數中, 內部是這樣的:
在這裏插入圖片描述
max_len 函數被傳入三個實參,類型爲 list,如上圖所示,lists 變量指向最下面的 tuple 實例。

接着往下運行, 就會出現lambda函數, 它的父函數是是f1, 也就是max_len函數。 那麼這裏的lambda函數裏面, v到底是啥? lambda的返回值又是啥?

我們看看這個v:
在這裏插入圖片描述
非常容易看出, v 指向 tuple 實例的第一個元素,指向的線和箭頭能非常直觀地反映出來。 那麼v就是[1, 2, 3], 而len(v) 就是3, 這個就是lambda函數的返回值。
在這裏插入圖片描述
然後, v指向元組中的下一個元素, 返回值是4
在這裏插入圖片描述
然後,v 指向 tuple 的最後一個元素 [8],返回值爲 1。
在這裏插入圖片描述
根據key確定的比較標準, max函數的返回值爲紅色字體指向的元素, 也就是返回[4, 5, 6, 7]
在這裏插入圖片描述
這其實就是lambda函數背後起的作用。 包括上面的sorted裏面的lambda, max裏面的lambda, 他們都是起的類似的作用。下面是完整的動畫演示:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章