二十九、深入Python中的collections模塊

@Author: Runsen

collections模塊是一個不用不知道,一用就上癮的模塊。這裡主要介紹OrderedDict類、defaultdict類、Counter類、namedtuple類和deque類。

@[TOC]

collections

collections的常用類型有:

  • 計數器(Counter)

  • 雙向隊列(deque)

  • 默認字典(defaultdict)

  • 有序字典(OrderedDict)

  • 可命名元組(namedtuple)

Counter

計數器(counter)以字典的形式返回序列中各個字符出現的次數,值為key,次數為value

Counter是對字典類型的補充,用於追蹤值得出現次數 。

import collections

counter = collections.Counter("My name is Runsen")
print(counter)

輸出如下

Counter({' ': 3, 'n': 3, 'e': 2, 's': 2, 'M': 1, 'y': 1, 'a': 1, 'm': 1, 'i': 1, 'R': 1, 'u': 1})

取得元素重複次數的值

print(counter[' '])
3

elements()取得計數器中的所有元素。

註:此處非所有元素集合,而是包含所有元素集合的迭代器.

counter = collections.Counter('abcabcabcdabcdef') 
print(counter)
# 輸出如下
Counter({'a': 4, 'b': 4, 'c': 4, 'd': 2, 'e': 1, 'f': 1})

print(counter.elements())
# 輸出如下
<itertools.chain object at 0x0000025B1477BF98>

print(list(counter.elements()))
# 輸出如下
['a', 'a', 'a', 'a', 'b', 'b', 'b', 'b', 'c', 'c', 'c', 'c', 'd', 'd', 'e', 'f']

將Counter按照value從大到小排列,獲取前N個元素,需要使用函數most_common

# most_common(N)數量從大到小排列,獲取前N個元素 
print(counter.most_common(3))
# 輸出如下
[('a', 4), ('b', 4), ('c', 4)]

sorted將Counter中的key進行排序,返回的是所有key的列表

# sorted()列出所有不同的元素並排序 
print(sorted(counter))

# 輸出如下
['a', 'b', 'c', 'd', 'e', 'f']

將Counter轉換成字符串,字符串的join方法可以解決。注意不是原來的模樣。

# 轉換成字符串 
print(''.join(counter.elements()))
# aaaabbbbccccddef
print(''.join(list(counter.elements())))

update()更新計數器,其實在原本的counter更新計數器,如果原來沒有,則新建key,如果有value則加一

# update()更新計數器,
d = collections.Counter('a') 
counter.update(d) 
print(counter) 
# 輸出如下
Counter({'a': 5, 'b': 4, 'c': 4, 'd': 2, 'e': 1, 'f': 1})

update()更新計數器,那麼subtract()相減計數器的values,即原來的計數器中的每一個元素的數量減去後添加的元素的數量

counter.subtract('abdabcabcg') 
print(counter)

# 輸出如下
Counter({'a': 2, 'c': 2, 'b': 1, 'd': 1, 'e': 1, 'f': 1, 'g': -1})

deque

deque支持從任意一端增加和刪除元素。更為常用的兩種結構,就是棧和隊列。

deque的常見操作

#定義一個空的雙向隊列
d = collections.deque()

#從右端增加元素
d.extend("Runsen") 
d.append("Maoli")
d.append("Python")
d.append("king")

#從左端增加元素
d.appendleft('left')
print(d)
# 輸出如下 (注意:extend和append的區別)
deque(['left', 'R', 'u', 'n', 's', 'e', 'n', 'Maoli', 'Python', 'king'])

# reverse()反轉隊列 
print(d.reverse())
d.reverse()
print(d)
# 輸出如下
None
deque(['king', 'Python', 'Maoli', 'n', 'e', 's', 'n', 'u', 'R', 'left'])


d.reverse()
d.extend(['qq','ww','ee']) 
print(d) 
# deque(['left', 'R', 'u', 'n', 's', 'e', 'n', 'Maoli', 'Python', 'king', 'qq', 'ww', 'ee'])


# count()計數 
print(d.count('R'))
# 輸出如下
1

# clear()清空隊列 
d.clear() 
print(d) 
# 輸出如下
deque([])

# index()取得元素下標 
print(d.index('Maoli'))
# 輸出如下
7

# insert()指定位置插入元素 
d.insert(1,'Runsen') 
print(d) 
# deque(['left', 'Runsen',R', 'u', 'n', 's', 'e', 'n', 'Maoli', 'Python', 'king', 'qq', 'ww', 'ee'])

OrderedDict

使用dict時要保持Key的順序,可以用OrderedDict。

from collections import OrderedDict 
dic = OrderedDict() 
dic['k1'] = 'v1' 
dic['k2'] = 'v2' 
dic['k3'] = 'v3' 
print(dic) 
# 輸出如下
OrderedDict([('k1', 'v1'), ('k2', 'v2'), ('k3', 'v3')])

# 字典所有的鍵 
print(dic.keys())
# 輸出如下

odict_keys(['k1', 'k2', 'k3'])
    
# 字典所有值 
print(dic.values())
# 輸出如下
odict_values(['v1', 'v2', 'v3'])
    
# items() 方法以列表返回可遍歷的(鍵, 值) 元組數組 
print(dic.items())

# 輸出如下
odict_items([('k1', 'v1'), ('k2', 'v2'), ('k3', 'v3')])
    

#pop()方法,刪除指定的鍵值 
dic.pop('k1')  
print(dic) 
# 輸出如下
OrderedDict([('k2', 'v2'), ('k3', 'v3')])


#popitem()方法,默認刪除字典最後一個元素 
dic.popitem() 
print(dic) 
# 輸出如下
OrderedDict([('k2', 'v2')])

# update()更新字典 
dic.update({'k1':'v1111','k10':'v10'}) 
print(dic) 
# 輸出如下
OrderedDict([('k2', 'v2'), ('k1', 'v1111'), ('k10', 'v10')])

OrderedDict和字典操作完全相同,區別在於OrderedDict的Key會按照插入的順序排列,不是Key本身排序

>>> from collections import OrderedDict
>>> d = dict([('a', 1), ('b', 2), ('c', 3)])
>>> d # dict的Key是無序的
{'a': 1, 'c': 3, 'b': 2}
>>> od = OrderedDict([('a', 1), ('b', 2), ('c', 3)])
>>> od # OrderedDict的Key是有序的
OrderedDict([('a', 1), ('b', 2), ('c', 3)])

defaultdict

在使用字典的時候, 如果在使用不存在的key的時候發生KeyError這樣的一個報錯, 這時候就該defaultdict登場了。

defaultdict接受一個工廠函數作為參數來構造:dict =defaultdict( factory_function)

這個factory_function可以是list、set、str等等,作用是當key不存在時,返回的是工廠函數的默認值,比如list對應[ ],str對應的是空字符串,set對應set( ),int對應0,如下舉例:

from collections import defaultdict

dict1 = defaultdict(int)
dict2 = defaultdict(set)
dict3 = defaultdict(str)
dict4 = defaultdict(list)
dict1[2] ='two'

print(dict1[1])
print(dict2[1])
print(dict3[1])
print(dict4[1])

# 輸出如下
0
set()

[]

defaultdict類接受類型名稱作為初始化函數的參數,這樣使得默認值的取值更加靈活。

s = 'mynameisrunsen'
d = collections.defaultdict(int)
for k in s:
    d[k] += 1
print(d)

# 輸出如下
defaultdict(<class 'int'>, {'m': 2, 'y': 1, 'n': 3, 'a': 1, 'e': 2, 'i': 1, 's': 2, 'r': 1, 'u': 1})

練習有如下值集合 [11,22,33,44,55,66,77,88,99,99]

下面將所有大於 55的值保存至字典的第一個key中,將小於 55 的值保存至第二個key的值中。

下面通過defaultdict默認字典對列表進行劃分。

all_list = [11,22,33,44,55,66,77,88,99]
dic = collections.defaultdict(list)
for i in all_list:
    if i > 55:
        dic['k1'].append(i)
    else:
        dic['k2'].append(i)
print(dic)
# 輸出如下
defaultdict(<class 'list'>, {'k2': [11, 22, 33, 44, 55], 'k1': [66, 77, 88, 99]})

也可以使用字典,具體代碼如下。

all_list = [11,22,33,44,55,66,77,88,99]
dic = {}
for i in all_list:
    if i > 55:
        if "k1" in dic.keys():
            dic['k1'].append(i)
        else:
            dic['k1'] = [i,]
    else:
        if "k2" in dic.keys():
            dic['k2'].append(i)
        else:
            dic['k2'] = [i,]
print(dic)
# 輸出如下
{'k2': [11, 22, 33, 44, 55], 'k1': [66, 77, 88, 99]}

namedtuple

namedtuple是用來創建一個自定義的tuple對象,並且規定了tuple元素的個數,並可以用屬性而不是索引來引用tuple的某個元素。

使用命名元組的步驟:

# 將元組封裝為一個類,可以通過字段名(屬性名)來訪問元組中的值
# 支持元組的所有操作
from collections import namedtuple
# 1、定義一個類
Runsen = namedtuple('Runsen', ['name','sex','age'])
# 2、創建對象
runsen = Runsen("Runsen", "帥男", 21)
# 3、獲取命名元組的值
print(runsen[1])    # 支持元組的索引取值  
print(runsen[-2:])  # 支持切片
print(runsen.name)  # 支持通過字段名來取值 
# _fields,獲取命名元組的所有屬性名
print(runsen._fields)
# _asdict方法,將元組轉化為字典
print(runsen._asdict())

# 輸出如下

帥男
('帥男', 21)
Runsen
('name', 'sex', 'age')
OrderedDict([('name', 'Runsen'), ('sex', '帥男'), ('age', 21)])

本文已收錄 GitHub,傳送門~ ,裏面更有大廠面試完整考點,歡迎 Star。

Tags: