データ型とアルゴリズムの要点
内容の確認日: 2026-10-04
この分野は『Python実践レシピ』の第 9 章 (データ型とアルゴリズム) に対応し、40 問中 5 問と、言語仕様に次いで出題の多い章です (bisect・pprint の節は出題範囲外)。
標準ライブラリの便利なデータ型と関数が中心で、「どのデータ型を使えば簡単に書けるか」「この関数の結果はどうなるか」が問われます。名前と動きをセットで覚えましょう。
ソート (sorted・sort・operator)
リストの sort() メソッドはリスト自体を並べ替え、戻り値は None です。組み込み関数 sorted() は、任意の反復可能オブジェクトから新しいリストを作ります。どちらも key (比べる値を返す関数) と reverse を指定できます。
Python のソートは安定ソートで、キーが同じ要素は元の順番のまま残ります。キーにタプルを返すと 1 つ目の値から順に比べるので、複数の条件で並べ替えられます。数値の降順と文字列の昇順を組み合わせるときは、数値に - を付けます。
operator.itemgetter(1) は要素の 1 番目を、operator.attrgetter("year") は属性を取り出す関数を作り、lambda の代わりに key に渡せます。引数を複数渡すと、それらのタプルを返します。
from operator import itemgetterscores = [("ann", 80), ("bob", 95), ("cat", 80), ("dan", 70)]print(sorted(scores, key=itemgetter(1)))print(sorted(scores, key=lambda s: (-s[1], s[0])))print(max(scores, key=itemgetter(1))[0], sorted("bBa"), sorted("bBa", key=str.lower))result = scores.sort()print(result)python3 main.py [('dan', 70), ('ann', 80), ('cat', 80), ('bob', 95)] [('bob', 95), ('ann', 80), ('cat', 80), ('dan', 70)] bob ['B', 'a', 'b'] ['a', 'b', 'B'] None
文字列は文字コード順に比べるため、大文字は小文字より前に来ます。大文字と小文字を区別せずに並べるには key=str.lower を指定します。
コンテナデータ型 (collections)
collections には、辞書・リスト・タプルを便利にしたデータ型があります。
・Counter: 要素の個数を数える辞書。most_common(n) で多い順に取り出し、ないキーは 0。+・- で個数を足し引きでき、- で 0 以下になった要素は消える。total() は合計 (Python 3.10 以降)
・defaultdict: ないキーを参照すると、指定した関数 (list・int など) で既定値を作って登録する
・deque: 両端への追加・削除が速い。appendleft・popleft・rotate。maxlen を指定すると、満杯のときに反対側が捨てられる
・namedtuple: 名前でアクセスできるタプル。イミュータブルで、変更には _replace
・OrderedDict: 順序付きの辞書。move_to_end で要素を末尾 (先頭) に移せる (通常の dict も Python 3.7 以降は挿入順を保持する)
・ChainMap: 複数の辞書を重ね、先に渡した辞書から順にキーを探す
from collections import Counter, defaultdict, deque, namedtuple, ChainMapwords = "the cat and the hat and the bat".split()counts = Counter(words)print(counts.most_common(2), counts["dog"], counts.total())by_initial = defaultdict(list)for w in sorted(set(words)): by_initial[w[0]].append(w)print(dict(by_initial))recent = deque(maxlen=3)for page in ["a", "b", "c", "d"]: recent.append(page)print(list(recent))User = namedtuple("User", "name age")u = User("ann", 30)print(u.name, u[1], u._replace(age=31))config = ChainMap({"debug": True}, {"debug": False, "port": 80})print(config["debug"], config["port"])python3 main.py [('the', 3), ('and', 2)] 0 8 {'a': ['and'], 'b': ['bat'], 'c': ['cat'], 'h': ['hat'], 't': ['the']} ['b', 'c', 'd'] ann 30 User(name='ann', age=31) True 80
列挙型 (enum)
Enum を継承したクラスで、名前付きの定数のまとまりを定義します。メンバーは Color.RED・Color(1) (値から)・Color["RED"] (名前から) で取得でき、name と value を持ちます。
・同じ値のメンバーを定義すると、後のものは最初のメンバーの別名になり、反復や len() では数えられない
・Enum のメンバーは値そのものとは等しくない (Color.RED == 1 は False)
・IntEnum・StrEnum は int・str のサブクラスで、数値・文字列と比較できる
・auto() は値を自動で割り当てる。Enum では 1, 2, 3...、StrEnum ではメンバー名の小文字、Flag では 1, 2, 4... (2 のべき乗)
・Flag は | で組み合わせ、in で含まれているかを調べられる
from enum import Enum, StrEnum, Flag, autoclass Status(Enum): ACTIVE = 1 STOPPED = 2 RUNNING = 1class Color(StrEnum): RED = auto() DARK_BLUE = auto()class Perm(Flag): READ = auto() WRITE = auto() EXEC = auto()print(Status(1), Status.RUNNING is Status.ACTIVE, len(Status), Status.ACTIVE == 1)print(Color.DARK_BLUE.value, Color.RED == "red")rw = Perm.READ | Perm.WRITEprint(Perm.WRITE in rw, Perm.EXEC in rw, Perm.EXEC.value)python3 main.py Status.ACTIVE True 2 False dark_blue True True False 4
イテレーターの組み合わせ (itertools)
itertools の関数はイテレーターを返すので、list() で中身を確認します。無限に続くものは islice で必要な数だけ取り出します。
・無限: count(開始, 間隔)・cycle(反復可能)・repeat(値)
・つなぐ・切る: chain・islice・zip_longest (長いほうに合わせ、足りない部分を fillvalue で埋める)
・まとめる: groupby (連続する同じ値をまとめる。全体で集計するには先にソートする)・batched(反復可能, n) (n 個ずつ。Python 3.12 以降)・pairwise (隣り合う 2 つずつ)
・計算: accumulate (累積)・starmap (タプルを引数に展開して呼ぶ)
・絞り込む: takewhile (条件が真の間だけ)・dropwhile・filterfalse・compress
・組み合わせ: product (直積)・permutations (順列)・combinations (組み合わせ)
import itertoolsprint(list(itertools.islice(itertools.count(10, 5), 3)))print([(k, len(list(g))) for k, g in itertools.groupby("aaabba")])print([(k, len(list(g))) for k, g in itertools.groupby(sorted("aaabba"))])print(list(itertools.batched("abcdefg", 3)), list(itertools.pairwise([1, 2, 3])))print(list(itertools.accumulate([1, 2, 3, 4])), list(itertools.takewhile(lambda x: x < 3, [1, 2, 5, 1])))print(len(list(itertools.permutations("abc", 2))), len(list(itertools.combinations("abc", 2))))python3 main.py [10, 15, 20] [('a', 3), ('b', 2), ('a', 1)] [('a', 4), ('b', 2)] [('a', 'b', 'c'), ('d', 'e', 'f'), ('g',)] [(1, 2), (2, 3)] [1, 3, 6, 10] [1, 2] 6 3
オブジェクトのコピー (copy)
b = a はコピーではなく、同じオブジェクトに別の名前を付けるだけです。コピーには 2 種類あります。
・浅いコピー (copy.copy(a)・a.copy()・a[:]・list(a)): 外側のオブジェクトだけを新しく作り、中の要素は元と同じオブジェクトを参照する
・深いコピー (copy.deepcopy(a)): 中の要素まで再帰的にコピーする
import copyoriginal = {"name": "ann", "tags": ["a"]}alias = originalshallow = original.copy()deep = copy.deepcopy(original)original["name"] = "bob"original["tags"].append("b")print(alias)print(shallow)print(deep)python3 main.py {'name': 'bob', 'tags': ['a', 'b']} {'name': 'ann', 'tags': ['a', 'b']} {'name': 'ann', 'tags': ['a']}
浅いコピーでも、キーに別の値を代入する変更 (name) は影響しませんが、共有している中のリストへの変更 (append) は見えてしまいます。
試験でよくある引っかけ
sort()の戻り値リストの
sort()はNoneを返します。並べ替えた結果が欲しいときはsorted()を使います。安定ソート
キーが同じ要素は元の順番のまま残ります。
reverse=Trueでも安定性は保たれます。Counterのないキー存在しないキーを参照しても
KeyErrorにはならず、0が返ります。defaultdictはキーを作るinで調べるだけではキーは作られませんが、d[キー]と参照した時点で既定値が登録されます。groupbyは連続した値だけ離れた位置の同じ値は別のグループになります。全体で集計するには先にソートするか、
Counterを使います。Enumの別名と比較同じ値のメンバーは別名になり数えられません。
Enumのメンバーは値そのものと==で等しくなりません。浅いコピーと中のリスト
浅いコピーでは中のリストが共有されるので、
appendは元にも反映されます。
問題で確認する
この分野の問題を、解説つきで読めます (登録不要)。
出典・参考
- Python エンジニア育成推進協会「Python 実践試験」(出題範囲)
- Python ドキュメント「ソート HOW TO」
- Python ドキュメント「collections」
- Python ドキュメント「enum」
- Python ドキュメント「itertools」
- Python ドキュメント「copy」
コード例は、実際に実行して結果を確認しています。