Python collections.deque

Python学習【365日チャレンジ!】278日目のマスターU(@Udemy11)です。

突然ですが、ジョン・フォン・ノイマンって知っていますか?

多分ほとんどの人が知らないんじゃないでしょうか?

では、アルベルト・アインシュタインは知っていますか?

こちらはほとんどの人が知っていると思います。

かの有名な相対性理論を唱え、ノーベル物理学賞を受賞した誰もが「天才」としてイメージする人物ですね。

実は、ほとんどの人が知らないジョン・フォン・ノイマンは、誰もが天才として認識しているアインシュタインが、世界一の天才だと認めた人物なんです。

現在使われているパソコンの元になった計算機は、ノイマン型と言われ、ノイマンが提唱した理論を元に作られていますし、昨日ちらっとふれた「ゲーム理論」はジョン・フォン・ノイマンが考え出した理論です。

電話帳を適当に開いたページに掲載されている電話番号の数字をすべて足した値を瞬時に計算することもできたそうで、ノイマン型のコンピューターを開発した際には、「俺の次に計算の速いやつができた」と言ったという逸話も残されているそうです。

そんな天才が考え出した「ゲーム理論」は非常に奥が深く、いろいろな学者が研究してたくさんの書籍が出版されているので、学習のための教材にはことかかないのですが、いかんせん理解するのがかなり難しいんですよね。

なので「ゲーム理論」は、のんびり学習したいと思います。

それでは今日も、Python学習を始めましょう。

昨日の復習

昨日は、文字をカウントしていろいろ便利に活用できるcollections.Counterを学習しました。

collections.Counterは、リストや辞書型データをカウントして、順番に表示したり、ファイルの中の文字列を抽出したりすることができました。

実際にどのような場面で活用するのかイメージがわかないのですが、今後実践に入ったときに使う場面が出てくるだろうとのことでした。

詳細については昨日の記事をごらんください。

今日は、メモリを効率よく扱って高速に処理ができるdequeを学習します。

queueとリストとdeque

queueは、マルチスレッド環境のメソッドがあるので、マルチスレッドで使うのがおすすめです。
リストは、インデックスの順番を指定して取り出したり値を出し入れすることに適しています。

dequeは、先頭から値を取り出したり、最後から取り出したりする時に高速に処理することができます。

それぞれに値を入れたり取り出したりしてみましょう。

import collections
import queue

q = queue.Queue()
lq = queue.LifoQueue()
l = []
d = collections.deque()

for i in range(3):
    q.put(i)
    lq.put(i)
    l.append(i)
    d.append(i)

for _ in range(3):
    print('FIFO queue = {}'.format(q.get()))
    print('LIFO queue = {}'.format(lq.get()))
    print('List       = {}'.format(l.pop(0)))
    print('deque      = {}'.format(d.popleft()))
    print()

インポートするライブラリはcollectionsqueueです。

4行目から順番にQueueLifoQueue、リスト、dequeの順番に入れ物を定義しています。

9行目からは、それぞれの入れ物に、3つの値[0, 1, 2]forループで回して代入しています。qlqにはputldにはappendを使って3つの値を入れています。

15行目からはそれぞれの入れ物の中から値を取り出して出力しています。

16行目は、ファーストインファーストアウトのqueueからgetを使って取り出します。

17行目は、ラストインファーストアウトのqueueから同じくgetを使って取り出します。

18行目は、リストなので、popを使って取り出しています。

19行目は、dequeからpopleftを使って左から順番に取り出しています。

20行目でそれぞれのforループの出力がわかりやすいようにprint()で改行しているので、出力結果は次のようになります。

出力結果

FIFO queue = 0
LIFO queue = 2
List       = 0
deque      = 0

FIFO queue = 1
LIFO queue = 1
List       = 1
deque      = 1

FIFO queue = 2
LIFO queue = 0
List       = 2
deque      = 2

ラストインファーストアウトのLifoQueueのみが最後に代入された2を最初に出力してていて、他の3つは、順番通り0から出力されているのがわかります。

rotate

queueの場合は、データを入れた最後の値から抽出するには、別のクラスLifoQueueを使う必要がありますが、dequeを使えば、取り出す際のメソッドを変えるだけで取り出す順番を変えることができます。

また、rotateを使えば、dequeに入れている値の順番をローテーションすることもできます。

import collections

d = collections.deque()

for i in range(3):
    d.append(i)

print(d)
d.rotate()
print(d)
d.rotate()
print(d)

出力結果

deque([0, 1, 2])
deque([2, 0, 1])
deque([1, 2, 0])

8行目のdの出力では0から順番になっていますが、9行目、11行目のrotatedの順番がローテーションされているのがわかります。

extend

extendを使って値を追加することもできます。

print(d)
d.extend('a')
print(d)
d.extendleft('l')
print(d)

出力結果

deque([0, 1, 2])
deque([0, 1, 2, 'a'])
deque(['l', 0, 1, 2, 'a'])

便宜上8行目からのコードのみ記述していますが、8行目の出力はdequeに入れた値の順番どおりに出力されています。

9行目のextend('a')aを追加しているので、10行目の出力で、値の最後にaが追加されているのがわかります。

11行目はextendleft('l')を使って、左(つまり先頭)にlを追加しているので、12行目の出力で、lが追加されているのがわかります。

clear

リストのメソッドで使えるclearを使えば、dequeに代入した値を一括消去することもできます。

print(d)
d.clear()
print(d)

出力結果

deque([0, 1, 2])
deque([])

8行目の出力は、dequeに代入された値が入っていますが、9行目でclearを使って、値を削除しているので、10行目の出力で、dequeの中身が空になっているのがわかるかと思います。

まとめ

入れ物の中に値を入れて、前から取り出したり、後ろから取り出したりできるqueueは便利ですが、dequeは、メモリを使って順番をローテーションしたり、値を前や後ろに追加したり、すべての値をクリアーしたり、高速な処理が可能なので、さらに便利な使い方ができます。

リストやqueueを使いつつ、これらを拡張したような使い方ができるdequeは、憶えておいて損はないでしょう。

それでは明日もGood Python!