Pythonのコレクションは、データのコレクションを格納するためのコンテナで、例えば、リスト、ディクト、セット、タプルなどです。
これらはビルトインコレクションです。
データのコレクションを格納するための追加のデータ構造を提供するいくつかのモジュールが開発されています。
その一つがPythonのcollectionsモジュールです。
Pythonコレクションモジュールは、組み込みのコレクションコンテナの機能性を向上させるために導入されました。
Python collectionsモジュールは2.4リリースで初めて導入されました。
このチュートリアルは、その最新の安定版(3.7バージョン)に基づいています。
コレクションモジュール
このチュートリアルでは、Pythonのコレクションモジュールから、最もよく使われる6つのデータ構造について説明します。
それらは以下の通りです。
- カウンター
- デフォルトディクト
- OrderedDict
- deque
- ChainMap
- namedtuple()
カウンター
Counter は dictionary オブジェクトのサブクラスです。
collectionsモジュールの Counter()
関数は、引数としてイテラブルまたはマッピングを受け取り、Dictionaryを返します。
このDictionaryでは、キーはイテラブルまたはマッピングの要素であり、値はその要素がイテラブルまたはマッピングに存在する回数である。
counterのインスタンスを生成する前に、
Counter` クラスをインポートする必要がある。
from collections import Counter
カウンタオブジェクトの作成
カウンタオブジェクトを作成するには、複数の方法があります。
最も簡単な方法は、引数なしで Counter()
関数を使う方法です。
cnt = Counter()
カウンタオブジェクトを作成するために、 Counter()
関数にイテラブル (リスト) を渡すことができます。
list = [1,2,3,4,1,2,6,7,3,8,1]
Counter(list)
最後に、Counter()
関数は引数として辞書を取ることができます。
この辞書では、キーの値はそのキーの ‘count’ であるべきです。
Counter({1:3,2:4})
以下のように、任意のカウンタ項目にそのキーでアクセスすることができます。
list = [1,2,3,4,1,2,6,7,3,8,1]
cnt = Counter(list)
print(cnt[1])
cnt[1]`と出力すると、1というカウントが得られる。
出力されます。
3
上記の例では、 cnt
は dict
のサブクラスである Counter
クラスのオブジェクトである。
そのため、 dict
クラスのすべてのメソッドを持っている。
それとは別に、Counter
は 3 つの追加機能を持っている。
- 要素
- Most_common([n])
- Subtract([interable-or-mapping])
エレメント()関数
elements()関数を使うと、
Counterオブジェクトに含まれる項目を取得することができる。
これはCounter` オブジェクトのすべての要素を含むリストを返す。
次の例を見てください。
cnt = Counter({1:3,2:4})
print(list(cnt.elements()))
出力してください。
出力: “`
[1, 1, 1, 2, 2, 2, 2]
ここでは、辞書を引数として `Counter` オブジェクトを生成している。この Counter オブジェクトでは、1 のカウントが 3、2 のカウントが 4 になっています。
イテレータは 1 の上で 3 回繰り返し、3 つの '1' を返し、2 の上で 4 回繰り返し、4 つの '2' をリストに返します。最後に、リストは `print` 関数を使って表示される。
##### Most_common()関数
関数 `Counter()` は順序未指定の辞書を返す。各要素のカウント数に応じてソートするには、`Counter` オブジェクトの `most_common()` 関数を使用します。
list = [1,2,3,4,1,2,6,7,3,8,1]
cnt = Counter(list)
print(cnt.most_common())
出力する。
[(1, 3), (2, 2), (3, 2), (4, 1), (6, 1), (7, 1), (8, 1)]
most_common` 関数が、要素のカウント数に基づいてソートされたリストを返していることがわかります。1 はカウントが 3 であるため、リストの最初の要素になります。
##### サブトラクト()関数
subtract()` はイテラブル(リスト)またはマッピング(辞書)を引数にとり、その引数を用いて要素数を減算する関数です。以下の例で確認してください。
cnt = Counter({1:3,2:4})
deduct = {1:1, 2:2}
cnt.subtract(deduct)
print(cnt)
出力。
Counter({1: 2, 2: 2})
最初に作った `cnt` オブジェクトは、'1' のカウントが 3 で、'2' のカウントが 4 であることがわかる。また、辞書 `deduct` には、キー '1' に対して値 '1'、キー '2' に対して値 '2' が格納されています。subtract()` 関数は、key '1' から 1 カウント、key '2' から 2 カウントを差し引いた値である。
#### デフォルトディクト
defaultdict` は Python の辞書と全く同じように動作しますが、存在しないキーにアクセスしようとしたときに `KeyError` を投げないという点が異なります。
その代わり、 `defaultdict` の生成時に引数として渡したデータ型の要素でキーを初期化します。このデータ型は `default_factory` と呼ばれます。
##### デフォルトディクトのインポート
まず、`collections`モジュールから `defaultdict` をインポートしてから使用する必要があります。
from collections import defaultdict
##### デフォルトディクトの作成
defaultdict` は `defaultdict()` コンストラクタで作成することができる。引数としてデータ型を指定する必要があります。以下のコードを確認してください。
nums = defaultdict(int)
nums[‘one’] = 1
nums[‘two’] = 2
print(nums[‘three’])
出力します。
0
この例では、`default_factory` として `int` が渡されています。int()`ではなく、`int` を渡していることに注意してください。次に、2つのキー、つまり 'one' と 'two' に対して値が定義されていますが、次の行では、まだ定義されていないキーにアクセスしようとしています。
通常の辞書では、これは `KeyError` を強制的に発生させます。しかし、 `defaultdict` は新しいキーを `default_factory` のデフォルト値、つまり `int` の場合は 0 で初期化します。したがって、プログラムが実行されると、0が表示されます。存在しないキーを初期化するというこの特殊な機能は、様々な場面で利用することができます。
例えば、"Mike, John, Mike, Anna, Mike, John, Mike, Britney, Smith, Anna, Smith" という名前のリストに含まれるそれぞれの名前の数を知りたい場合を考えてみましょう。
from collections import defaultdict
count = defaultdict(int)
names_list = “Mike John Mike Anna Mike John John Mike Mike Britney Smith Anna Smith”.split()
for names in names_list:
count[names] +=1
print(count)
出力する。
defaultdict(, {‘Mike’: 5, ‘Britney’: 1, ‘John’: 3, ‘Smith’: 2, ‘Anna’: 2})
まず、int を `default_factory` とする `defaultdict` を作成します。names_list` には、何度も繰り返される名前のセットが含まれます。split()` 関数は、与えられた文字列をリストにして返します。この関数は、空白文字に出会うたびに文字列を分割し、単語をリストの要素として返します。ループの中では、リストの各項目が `defaultdict` に `count` という名前で追加され、 `default_factory` に基づいて 0 に初期化されます。もし、同じ要素に再び出会った場合は、ループを継続しながら、その要素のカウントをインクリメントしていく。
#### The OrderedDict
OrderedDict` は、キーが挿入された順番を維持する辞書です。つまり、あるキーの値を後で変更しても、キーの位置は変更されません。
##### Import OrderedDict
OrderedDict` を使用するには、collections モジュールからインポートする必要があります。
from collections import OrderedDict
##### OrderedDictを作成する
OrderedDict オブジェクトを作成するには、`OrderedDict()` コンストラクタを用います。以下のコードでは、引数なしで `OrderedDict` を生成します。その後、いくつかの項目が挿入されます。
od = OrderedDict()
od[‘a’] = 1
od[‘b’] = 2
od[‘c’] = 3
print(od)
出力
出力:```
OrderedDict([('a', 1), ('b', 2), ('c', 3)])
ループを使って各要素にアクセスすることもできます。
次のコードを見てください。
for key, value in od.items():
print(key, value)
出力
a 1
b 2
c 3
次の例は、 OrderedDict
と Counter
を組み合わせた興味深い使用例です。
ここでは、リストから Counter
を作成し、そのカウントに基づいて OrderedDict
に要素を挿入しています。
最も頻出する文字が最初のキーとして挿入され、最も頻出しない文字が最後のキーとして挿入されます。
list = ["a","c","c","a","b","a","a","b","c"]
cnt = Counter(list)
od = OrderedDict(cnt.most_common())
for key, value in od.items():
print(key, value)
出力する。
a 4
c 3
b 2
デク
deque` はアイテムの挿入と削除に最適化されたリストです。
Dequeをインポートする
deque クラスを使用するには、事前に collections
モジュールから deque
クラスをインポートしておく必要がある。
from collections import deque
Dequeの作成
deque は deque()
コンストラクタで生成できます。
引数としてリストを渡す必要があります。
list = ["a","b","c"]
deq = deque(list)
print(deq)
出力
deque(['a', 'b', 'c'])
Dequeへの要素の挿入
作成した deq
の両端に要素を挿入するのは簡単です。
dequeの右端に要素を追加するには、 append()
メソッドを使用する必要があります。
dequeの先頭に要素を追加するには、appendleft()
メソッドを使用します。
deq.append("d")
deq.appendleft("e")
print(deq)deque
出力。
deque(['e', 'a', 'b', 'c', 'd'])
dが deq の末尾に、
e` が deq の先頭に追加されているのがわかると思います。
Dequeから要素を削除する #### Dequeから要素を削除する
要素の削除は、要素の挿入と似ています。
要素を挿入するのと同じように、要素を削除することができます。
要素を右端から削除するには pop()
関数を、左端から削除するには popleft()
関数を使用します。
deq.pop()
deq.popleft()
print(deq)
出力
deque(['a', 'b', 'c'])
deq` からは最初の要素と最後の要素の両方が削除されていることがわかるでしょう。
Dequeをクリアする
dequeからすべての要素を削除したい場合は、clear()
関数を使用します。
list = ["a","b","c"]
deq = deque(list)
print(deq)
print(deq.clear())
出力
出力: “`
deque([‘a’, ‘b’, ‘c’])
None
出力結果を見ると、最初は3つの要素を持つキューが存在していることがわかります。clear()` 関数を適用すると、deque はクリアされ、出力には `none` と表示されています。
##### Dequeの要素を数える
特定の要素のカウントを求めるには、関数 `count(x)` を使用します。引数として、カウントを求める要素を指定する必要があります。
list = [“a”,”b”,”c”]
deq = deque(list)
print(deq.count(“a”))
出力する。
1
上の例では、aのカウントは1であるから、'1'と出力される。
#### ChainMap
ChainMap` は複数の辞書やマッピングを結合するために使用されます。これは、辞書のリストを返します。
##### チェーンマップのインポート
ChainMap` を使用する前に、`collections` モジュールから `ChainMap` をインポートする必要があります。
from collections import ChainMap
##### ChainMapの作成
チェーンマップを作成するには、`ChainMap()` コンストラクタを使用します。引数として、結合する辞書を渡します。
dict1 = { ‘a’ : 1, ‘b’ : 2 }
dict2 = { ‘c’ : 3, ‘b’ : 4 }
chain_map = ChainMap(dict1, dict2)
print(chain_map.maps)
出力
[{‘b’: 2, ‘a’: 1}, {‘c’: 3, ‘b’: 4}]
出力として、辞書のリストが表示されます。チェーンマップの値にはキー名でアクセスできます。
print(chain_map[‘a’])
出力されます。
1
もう一つの重要な点は、`ChainMap`は、関連する辞書が更新されると、その値も更新されることである。例えば、`dict2`の'c'の値を'5'に変更すると、`ChainMap`の値も変更されることがわかります。
dict2[‘c’] = 5
print(chain_map.maps)
出力
[{‘a’: 1, ‘b’: 2}, {‘c’: 5, ‘b’: 4}]
##### ChainMapからKeyとValueを取得する
ChainMap` のキーにアクセスするには、 `keys()` 関数を使用します。同様に、以下のように `values()` 関数を使用して、要素の値にアクセスすることができます。
dict1 = { ‘a’ : 1, ‘b’ : 2 }
dict2 = { ‘c’ : 3, ‘b’ : 4 }
chain_map = ChainMap(dict1, dict2)
print (list(chain_map.keys()))
print (list(chain_map.values()))
出力する。
出力: ```
['b', 'a', 'c']
[2, 1, 3]
出力されたキー ‘b’ の値は、dict1
のキー ‘b’ の値であることに注意してください。
経験則として、1つのキーが複数の辞書に現れる場合、 ChainMap
はそのキーに対して最初の辞書から値を取る。
ChainMapに新しい辞書を追加する。
既存の ChainMap
に新しい辞書を追加したい場合は、 new_child()
関数を使用してください。
これは、新しく追加された辞書を含む新しい ChainMap
を作成します。
dict3 = {'e' : 5, 'f' : 6}
new_chain_map = chain_map.new_child(dict3)
print(new_chain_map)
出力されます。
出力: “`
ChainMap({‘f’: 6, ‘e’: 5}, {‘a’: 1, ‘b’: 2}, {‘b’: 4, ‘c’: 3})
新しい辞書が `ChainMap` リストの先頭に追加されたことに注意してください。
#### namedtuple()
namedtuple()` はタプルの各ポジションに対応した名前を持つタプルを返します。通常のタプルの最大の問題の1つは,タプルオブジェクトの各フィールドのインデックスを覚えておかなければならないことです.これは明らかに困難です。この問題を解決するために導入されたのが `namedtuple` です。
##### 名前付きタプルのインポート
namedtuple` を使用する前に、 `collections` モジュールからインポートする必要があります。
from collections import namedtuple
##### 名前付きタプルの作成
from collections import namedtuple
Student = namedtuple(‘Student’, ‘fname, lname, age’)
s1 = Student(‘John’, ‘Clarke’, ’13’)
print(s1.fname)
出力する。
Student(fname=’John’, lname=’Clarke’, age=’13’)
この例では、`namedtuple` オブジェクト `Student` が宣言されています。定義されたフィールド名で `Student` クラスの任意のインスタンスのフィールドにアクセスすることができます。
#### Listを用いた名前付きタプルの作成
`namedtuple()` 関数は、各値を個別に渡す必要があります。その代わりに、 `_make()` を使ってリストで `namedtuple` のインスタンスを作成することができます。以下のコードを確認してください。
s2 = Student._make([‘Adam’,’joe’,’18’])
print(s2)
出力します。
Student(fname=’Adam’, lname=’joe’, age=’18’)
##### 既存のインスタンスを利用した新規インスタンスの作成
既存のインスタンスから `OrderedDict` インスタンスを作成するには、`_asdict()` 関数を使用することができます。
s2 = s1._asdict()
print(s2)
出力
出力: ```
OrderedDict([('fname', 'John'), ('lname', 'Clarke'), ('age', '13')])
フィールドの値を変更する(Field Values with _replace() Function)
インスタンスのフィールドの値を変更するには、_replace()
関数を使用します。
このとき、_replace()
関数は新しいインスタンスを作成することに注意してください。
既存のインスタンスの値を変更するものではありません。
s2 = s1._replace(age='14')
print(s1)
print(s2)
出力
Student(fname='John', lname='Clarke', age='13')
Student(fname='John', lname='Clarke', age='14')
結論
これで、Collectionsモジュールのチュートリアルを終了します。
コレクションモジュールの重要なトピックをすべて説明しました。
Pythonのコレクションモジュールは、Javaのコレクションライブラリと比較すると、まだ改良が必要です。
そのため、今後のバージョンアップで多くの変更が行われることが予想されます。
参考文献
- Python Collection Module Documentation
</class