Pythonユーティリティライブラリの紹介
bisectは順序付きリストを管理します
bisectモジュールには、bisectとinsortという2つの主要な関数が含まれています。どちらの関数も、バイナリ検索アルゴリズムを使用して、順序付けられたシーケンスで要素を見つけて挿入します。
# BEGIN BISECT_DEMO
import bisect
import sys
HAYSTACK = [1, 4, 5, 6, 8, 12, 15, 20, 21, 23, 23, 26, 29, 30]
NEEDLES = [0, 1, 2, 5, 8, 10, 22, 23, 29, 30, 31]
ROW_FMT = '{0:2d} @ {1:2d} {2}{0:<2d}'
def demo(bisect_fn):
for needle in reversed(NEEDLES):
position = bisect_fn(HAYSTACK, needle) # <1>
offset = position * ' |' # <2>
print(ROW_FMT.format(needle, position, offset)) # <3>
if __name__ == '__main__':
if sys.argv[-1] == 'left': # <4>
bisect_fn = bisect.bisect_left
else:
bisect_fn = bisect.bisect
print('DEMO:', bisect_fn.__name__) # <5>
print('haystack ->', ' '.join('%2d' % n for n in HAYSTACK))
demo(bisect_fn)
# END BISECT_DEMO
'''
DEMO: bisect
haystack -> 1 4 5 6 8 12 15 20 21 23 23 26 29 30
31 @ 14 | | | | | | | | | | | | | |31
30 @ 14 | | | | | | | | | | | | | |30
29 @ 13 | | | | | | | | | | | | |29
23 @ 11 | | | | | | | | | | |23
22 @ 9 | | | | | | | | |22
10 @ 5 | | | | |10
8 @ 5 | | | | |8
5 @ 3 | | |5
2 @ 1 |2
1 @ 1 |1
0 @ 0 0
'''
import bisect
import random
SIZE = 7
random.seed(1729)
my_list = []
for i in range(SIZE):
new_item = random.randrange(SIZE*2)
bisect.insort(my_list, new_item)
print('%2d ->' % new_item, my_list)
'''
10 -> [10]
0 -> [0, 10]
6 -> [0, 6, 10]
8 -> [0, 6, 8, 10]
7 -> [0, 6, 7, 8, 10]
2 -> [0, 2, 6, 7, 8, 10]
10 -> [0, 2, 6, 7, 8, 10, 10]
'''
その中で、bisect関数とinsort関数(基本的にはbisect_leftとinsort_left)のbisect_rightとinsort_rightは類似しています。これらの違いは、リストに同じ計算結果の要素がある場合、新しい要素がこれらの要素の左側または右側に挿入されることです。
配列効率的な数値記憶構造
リストは柔軟でシンプルですが、コンテナー構造です(特定の値ではなく、対応する要素へのポインターです。これにより、より広く使用されますが、より多くのアクセスとストレージが必要になります)。 、したがって、格納されたコンテンツが値のみの場合、floatオブジェクトではなく配列を使用できますが、数値の機械翻訳です。同時に、配列はほとんどすべてのリスト操作をサポートします。
from array import array
from random import random
floats = array('d', (random() for i in range(10**7)))
print(floats[-1])
# 0.7030774022684948
fp = open("floats.bin", 'wb')
floats.tofile(fp)
fp.close()
floats = array('d')
fp = open("floats.bin", 'wb')
floats2.fromfile(fp, 10**7)
fp.close()
print(floats2[-1])
# 0.7030774022684948
print(floats == floats2)
# True
配列では特定のタイプの値のみを格納できるため、格納するデータ型は作成時に指定する必要があります。特定のタイプ名を以下の表に示します。
メモリビューメモリビュー
memoryviewを使用すると、ユーザーはコンテンツをコピーせずに同じ配列の異なるスライスを操作できます。
import array
numbers = array.array('h', [-2, -1, 0, 1, 2])
memv = memoryview(numbers)
print(len(memv)) # 5
print(memv[0]) # -2
memv_oct = memv.cast('B')
print(memv_oct.tolist()) # [254, 255, 255, 255, 0, 0, 1, 0, 2, 0]
memv_oct[5] = 4
print(numbers)
# array('h', [-2, -1, 1024, 1, 2])
データ番号の別のエイリアスmemvが作成され、データ型変換は後でmemv.castを介して実現されました。同時に、memvを変更すると、元のデータも変更されます。
デキュー
collections.dequeクラスは、両端から要素をすばやく追加および削除できるスレッドセーフなデータ構造です。また、「最近使用された要素」を格納するデータ型が必要な場合は、dequeも適しています。これは、双方向キューを作成するときにキューのサイズを指定できるためです。キューがいっぱいの場合は、期限切れの要素を逆方向から削除して、最後に新しい要素を追加することもできます。
from collections import deque
dq = deque(range(10), maxlen=10)
print(dq) # deque([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxlen=10)
dq.rotate(3)
print(dq) # deque([7, 8, 9, 0, 1, 2, 3, 4, 5, 6], maxlen=10)
dq.rotate(-4)
print(dq) # deque([1, 2, 3, 4, 5, 6, 7, 8, 9, 0], maxlen=10)
dq.appendleft(-1)
print(dq) # deque([-1, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxlen=10)
dq.extend([11, 22, 33])
print(dq) # deque([3, 4, 5, 6, 7, 8, 9, 11, 22, 33], maxlen=10)
dq.extendleft([10, 20, 30, 40])
print(dq) # deque([40, 30, 20, 10, 3, 4, 5, 6, 7, 8], maxlen=10)
dequeはほとんどすべてのリスト操作をサポートしていますが、dequeはpop(p)操作をサポートしていません。
キュー
同期(スレッドセーフ)クラスQueue、LifoQueue、およびPriorityQueueを提供し、さまざまなスレッドがこれらのデータクラスを使用して情報を交換できます。これら3つのクラスの構築メソッドには、オプションのパラメーターmaxsizeがあります。これは、キューのサイズを制限するための入力として正の整数を受け入れます。しかし、満杯になっても、これらのクラスはスペースを作るために古い要素を捨てません。逆に、キューがいっぱいになると、別のスレッドが要素を削除してスペースを確保したことを認識して、キューがロックされます。この機能により、これらのクラスはアクティブなスレッドの数を制御するのに非常に適しています。
マルチプロセッシングパッケージは、queue.Queueに似た独自のキューを実装し、プロセス間通信用に設計されています。特別なmultiprocessing.JoinableQueueタイプもあり、タスク管理をより便利にすることができます。
asyncioパッケージには、Queue、LifoQueue、PriorityQueue、JoinableQueueが含まれており、これらのクラスは、非同期プログラミングでのタスク管理に特別な便宜を提供します。