Remrinのpython攻略日記

python3に入門しました。python3についてあれこれとサンプルコードとか。

collectionsライブラリ

標準ライブラリのcollectionsには便利なデータ型があります。

namedtuple() タプル風 名前付きフィールドを持つタプルを作成するファクトリ関数
deque リスト風 両端における append や pop を高速に行えるリスト風のコンテナ
ChainMap 辞書風 複数のマッピングの一つのビューを作成する辞書風のクラス
Counter 辞書 ハッシュ可能なオブジェクトを数え上げる辞書のサブクラス
OrderedDict 辞書 項目が追加された順序を記憶する辞書のサブクラス
defaultdict 辞書 ファクトリ関数を呼び出して存在しない値を供給する辞書のサブクラス
UserDict 辞書 辞書のサブクラス化を簡単にする辞書オブジェクトのラッパ
UserList リスト リストのサブクラス化を簡単にするリストオブジェクトのラッパ
UserString 文字列 文字列のサブクラス化を簡単にする文字列オブジェクトのラッパ

 
○Counter (dict型のサブクラス)
頻度のカウントをし、辞書型オブジェクトを作る。
 
使用例

# -*- coding: utf-8 -*-
from collections import Counter

text = "あかねさす むらさきのゆき しめのゆき のもりはみずや きみがそでふる"
text = text.replace(" ", "")

c = Counter(text)        #文字をカウントするCounterオブジェクト
print(c)                 #Counter({'き': 4, 'の': 3, 'ゆ': 2,...
print(c.most_common(1))  #[('き', 4)] 最頻出の要素を表示

 
Counterオブジェクトは辞書型のサブクラスなので、辞書と同様の扱いができ、
辞書オブジェクトのメソッドもほぼすべて使える。
存在しない要素に対してはKeyErrorではなく、0を返す。

print(c["き"])  #4
print(c["の"])  #3
print(c["い"])  #0 存在しないときはゼロ
print(len(c))   #23

 
・Counterの生成

c = Counter()                   # a new, empty counter
c = Counter('akasatana')        # a new counter from an iterable
c = Counter({'あ': 4, 'い': 2}) # a new counter from a mapping
c = Counter(あ=4, い=8)         # a new counter from keyword args

print(c)                        #Counter({'い': 8, 'あ': 4})

 
辞書型に追加されたメソッドは3つで、most_common(), elements(), subtract()
・Counter.most_common(n)
 nを省くと頻度の多い順に(key, value)のタプルをすべて並べたリストを得る。
 引数nを指定すると、頻度順にn個のタプルのリストを得る。

print(c.most_common(2))      #[('き', 4), ('の', 3)]
print(c.most_common()[0])    #('き', 4)
print(c.most_common()[0][0]) #き
print(c.most_common()[0][1]) #4

 
・Counter.elements()
それぞれの要素をカウントの回数生成するイテレータ

c = Counter(a=4, b=2, c=0, d=-2)
>>> sorted(c.elements())   #['a', 'a', 'a', 'a', 'b', 'b']

カウントが0や負の場合は無視される。
 
・Counter.subtract(iterable)

c = Counter(a=4, b=2, c=0)
d = Counter(a=1, b=2, c=3)
c.subtract(d)
print(c)      #Counter({'a': 3, 'b': 0, 'c': -3})

 
・update(iterable or mapping)メソッドはカウントを置き換えるのではなく、追加。
 引数は{"a":1, "b":1}のようなmappingか、
 iterableのときは(key, value)対のシーケンスではなく、要素のみのシーケンス。

c = Counter(a=4, b=2, c=0)
c.update({"a":1, "b":1})
print(c)                   #Counter({'a': 5, 'b': 3, 'c': 0})

c.update(["a", "c", "c"])
print(c)                   #Counter({'a': 6, 'b': 3, 'c': 2})

 
・数学演算

c = Counter(a=3, b=1)
d = Counter(a=1, b=2)
c1 = c + d               # add two counters together:  c[x] + d[x]
print(c1)                # Counter({'a': 4, 'b': 3})
c2 = c - d               # subtract (keeping only positive counts)
print(c2)                # Counter({'a': 2})
c3 = c & d               # intersection:  min(c[x], d[x]) 
print(c3)                # Counter({'b': 1, 'a': 1})
c4 = c | d               # union:  max(c[x], d[x])
print(c4)                # Counter({'a': 3, 'b': 2})

 
・単項加減

c = Counter(a=2, b=-4, c=0)
print(c)   #Counter({'a': 2, 'c': 0, 'b': -4})

c1 = +c    #カウントが正の要素だけ残す
print(c1)  #Counter({'a': 2})

c2 = -c    #カウントの正負を逆にし、正の要素を残す
print(c2)  #Counter({'b': 4})

 
・カウントの削除

c = Counter(a=1, b=2, c=3)
c["c"] = 0    # カウントを0にするだけで、削除されない
print(c)      # Counter({'b': 2, 'a': 1, 'c': 0})

c = +c        # カウントが正でない要素を削除
print(c)      # Counter({'b': 2, 'a': 1})

del c["b"]    # delで要素を削除できる
print(c)      # Counter({'a': 1})

del c         # cそのものを削除し、メモリ解放
#print(c)     # NameError: name 'c' is not defined

 
・よくあるパターン

sum(c.values())                 # total of all counts
c.clear()                       # reset all counts
list(c)                         # list unique elements
set(c)                          # convert to a set
dict(c)                         # convert to a regular dictionary
c.items()                       # convert to a list of (elem, cnt) pairs
Counter(dict(list_of_pairs))    # convert from a list of (elem, cnt) pairs
c.most_common()[:-n-1:-1]       # n least common elements
+c                              # remove zero and negative counts

 

deque

 リストをキューとして使う。
 FIFO(first in first out)として使う。
 pop(0)でリスト型の最初の要素を取り出せるが、
 python標準のリスト型は左端の要素の追加・取り出し動作が遅いのでcollectionsのdequeを使うのがよい。
 dequeはリストの両端での追加、取り出しが高速に実行できる。

from collections import deque
q = deque([1, 3, 5])
q.append(7)
q.appendleft(-1)
print(q)           # deque([-1, 1, 3, 5, 7])

print(q.pop())     # 7
print(q.popleft()) # -1
print(q)           # deque([1, 3, 5])

他のデータ型についてはそのうち追加 

参考:
pythonドキュメント collectionsライブラリ