LESSON 30分

Pythonのデータ構造

ストーリー

「Pythonが強いのはデータ処理だ」田中先輩が言った。

「list、dict、set... これらのデータ構造と、 リスト内包表記という書き方を覚えれば、 TypeScriptの配列操作より短いコードでデータ処理ができる」


list(リスト)

TypeScriptの配列 Array に相当します。

python
# リストの作成
fruits: list[str] = ["apple", "banana", "cherry"]
numbers: list[int] = [1, 2, 3, 4, 5]
mixed = [1, "hello", True, 3.14]  # 異なる型も入る(推奨しない)

# 基本操作
fruits.append("date")          # 末尾に追加
fruits.insert(0, "avocado")   # 先頭に追加
removed = fruits.pop()         # 末尾から取り出し
fruits.remove("banana")        # 値を指定して削除

# アクセス
print(fruits[0])    # 先頭
print(fruits[-1])   # 末尾
print(fruits[1:3])  # スライス(インデックス1〜2)

# 検索
print("apple" in fruits)      # True
print(fruits.index("cherry"))  # インデックスを取得
print(len(fruits))             # 要素数

# ソート
numbers.sort()                 # 昇順(元のリストを変更)
numbers.sort(reverse=True)     # 降順
sorted_nums = sorted(numbers)  # 新しいリストを返す(元は変更しない)

dict(辞書)

TypeScriptのオブジェクト / Record<K, V> に相当します。

python
# 辞書の作成
user: dict[str, str | int] = {
    "name": "田中太郎",
    "age": 28,
    "department": "開発部",
}

# アクセス
print(user["name"])           # "田中太郎"
print(user.get("role", "なし"))  # キーがなければデフォルト値を返す

# 追加・更新
user["email"] = "tanaka@example.com"  # 追加
user["age"] = 29                       # 更新

# 削除
del user["department"]
age = user.pop("age")  # 取り出して削除

# 繰り返し
for key in user:
    print(f"{key}: {user[key]}")

for key, value in user.items():
    print(f"{key}: {value}")

# キーの存在チェック
if "name" in user:
    print(user["name"])

# キーと値の一覧
print(user.keys())    # dict_keys([...])
print(user.values())  # dict_values([...])

tuple(タプル)

変更不可(イミュータブル)なリストです。TypeScriptのタプル型に相当します。

python
# タプルの作成
point: tuple[int, int] = (10, 20)
rgb: tuple[int, int, int] = (255, 128, 0)

# アクセス
print(point[0])  # 10
print(point[1])  # 20

# アンパック(分割代入)
x, y = point
r, g, b = rgb

# 関数から複数の値を返す
def divide(a: int, b: int) -> tuple[int, int]:
    return a // b, a % b  # 商と余り

quotient, remainder = divide(10, 3)
print(f"商: {quotient}, 余り: {remainder}")  # "商: 3, 余り: 1"

# タプルは変更不可
# point[0] = 30  # エラー!

set(集合)

重複のない要素の集まりです。

python
# セットの作成
colors: set[str] = {"red", "green", "blue"}
numbers: set[int] = {1, 2, 3, 4, 5}

# 追加・削除
colors.add("yellow")
colors.discard("red")  # 存在しなくてもエラーにならない

# 集合演算
a = {1, 2, 3, 4, 5}
b = {4, 5, 6, 7, 8}

print(a & b)   # 積集合: {4, 5}
print(a | b)   # 和集合: {1, 2, 3, 4, 5, 6, 7, 8}
print(a - b)   # 差集合: {1, 2, 3}

# 重複除去に便利
names = ["田中", "佐藤", "田中", "鈴木", "佐藤"]
unique_names = list(set(names))  # ["田中", "佐藤", "鈴木"]

リスト内包表記(List Comprehension)

TypeScriptの map/filter をPythonらしく書く方法です。

python
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# map: 各要素を変換
doubled = [n * 2 for n in numbers]
# [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

# filter: 条件で絞り込み
evens = [n for n in numbers if n % 2 == 0]
# [2, 4, 6, 8, 10]

# map + filter: 変換と絞り込みを同時に
even_doubled = [n * 2 for n in numbers if n % 2 == 0]
# [4, 8, 12, 16, 20]

TypeScriptとの比較

typescript
// TypeScript
const doubled = numbers.map((n) => n * 2);
const evens = numbers.filter((n) => n % 2 === 0);
const evenDoubled = numbers.filter((n) => n % 2 === 0).map((n) => n * 2);
python
# Python
doubled = [n * 2 for n in numbers]
evens = [n for n in numbers if n % 2 == 0]
even_doubled = [n * 2 for n in numbers if n % 2 == 0]

辞書内包表記

python
# 辞書内包表記
users = [
    {"name": "田中", "age": 28},
    {"name": "佐藤", "age": 35},
    {"name": "鈴木", "age": 22},
]

# 名前をキー、年齢を値とする辞書
name_age = {u["name"]: u["age"] for u in users}
# {"田中": 28, "佐藤": 35, "鈴木": 22}

ジェネレータ式

大量データを扱う時に、メモリを節約できる仕組みです。

python
# リスト内包表記: 全てメモリに格納
squares_list = [n ** 2 for n in range(1000000)]  # メモリをたくさん使う

# ジェネレータ式: 必要な時に1つずつ生成
squares_gen = (n ** 2 for n in range(1000000))  # メモリを節約

# ジェネレータは for ループで使える
for square in squares_gen:
    if square > 100:
        break
    print(square)

# sum, max, min と組み合わせる
total = sum(n ** 2 for n in range(100))

実践: データ処理

python
# 売上データの分析
sales = [
    {"product": "Widget A", "quantity": 10, "price": 1500, "region": "東京"},
    {"product": "Widget B", "quantity": 5, "price": 2000, "region": "大阪"},
    {"product": "Widget A", "quantity": 8, "price": 1500, "region": "東京"},
    {"product": "Widget C", "quantity": 3, "price": 3000, "region": "名古屋"},
]

# 合計売上
total = sum(s["quantity"] * s["price"] for s in sales)
print(f"合計: {total:,}円")

# 東京の売上だけ
tokyo_sales = [s for s in sales if s["region"] == "東京"]

# 商品別集計
from collections import Counter
products = Counter(s["product"] for s in sales)
print(products)  # Counter({"Widget A": 2, "Widget B": 1, "Widget C": 1})

# 地域別合計
region_totals: dict[str, int] = {}
for s in sales:
    region = s["region"]
    revenue = s["quantity"] * s["price"]
    region_totals[region] = region_totals.get(region, 0) + revenue
print(region_totals)

まとめ

データ構造TypeScript相当特徴
listArray順序あり、変更可能
dictObject/Recordキーと値のペア
tupleTuple型変更不可、固定長
setSet重複なし
内包表記map/filterPythonらしい簡潔な書き方

チェックリスト

  • list の基本操作(append, pop, slice)を使える
  • dict でキーと値を操作できる
  • tuple で複数の値を返す関数を書ける
  • リスト内包表記で map/filter 相当の処理を書ける
  • TypeScriptのデータ構造との対応を理解した

次のステップへ

Pythonのデータ構造を学びました。

次のセクションでは、他人のコードを読む技術を学びます。 TypeScriptとPythonの両方で、既存のコードベースを効率的に理解する方法を身につけましょう。


推定読了時間: 30分