10日で覚えるPythonDay 4: データ構造
books.chapter 410日で覚えるPython

Day 4: データ構造

今日学ぶこと

  • リスト(list): 順序付きで変更可能なコレクション
  • タプル(tuple): 順序付きで変更不可のコレクション
  • 辞書(dict): キーと値のペア
  • セット(set): 重複のないコレクション
  • リスト内包表記

リスト(list)

リストは、複数の値を順序付きで格納できる、最もよく使われるデータ構造です。

flowchart LR
    subgraph List["リスト fruits"]
        A["'apple'"] --> B["'banana'"] --> C["'cherry'"]
    end

    subgraph Index["インデックス"]
        I0["0"] --> I1["1"] --> I2["2"]
    end

    style List fill:#3b82f6,color:#fff

リストの作成

# 空のリスト
empty = []
also_empty = list()

# 値を持つリスト
fruits = ["apple", "banana", "cherry"]
numbers = [1, 2, 3, 4, 5]
mixed = [1, "hello", 3.14, True]  # 異なる型も混在可能

要素へのアクセス

fruits = ["apple", "banana", "cherry", "date"]

# インデックスでアクセス
print(fruits[0])   # apple(最初)
print(fruits[2])   # cherry
print(fruits[-1])  # date(最後)
print(fruits[-2])  # cherry(最後から2番目)

スライス

fruits = ["apple", "banana", "cherry", "date", "elderberry"]

print(fruits[1:4])   # ['banana', 'cherry', 'date']
print(fruits[:3])    # ['apple', 'banana', 'cherry']
print(fruits[2:])    # ['cherry', 'date', 'elderberry']
print(fruits[::2])   # ['apple', 'cherry', 'elderberry'](1つ飛ばし)
print(fruits[::-1])  # 逆順

リストの変更

fruits = ["apple", "banana", "cherry"]

# 要素の変更
fruits[1] = "blueberry"
print(fruits)  # ['apple', 'blueberry', 'cherry']

# 要素の追加
fruits.append("date")        # 末尾に追加
fruits.insert(1, "apricot")  # 指定位置に挿入

# 要素の削除
fruits.remove("apple")  # 値で削除
del fruits[0]           # インデックスで削除
popped = fruits.pop()   # 末尾を取り出して削除
popped = fruits.pop(0)  # 指定位置を取り出して削除

リストの主要メソッド

メソッド 説明 例
append(x) 末尾に追加 list.append(5)
insert(i, x) 位置iに挿入 list.insert(0, 5)
remove(x) 値xを削除 list.remove(5)
pop(i) 位置iを取り出す list.pop(0)
index(x) 値xの位置を返す list.index(5)
count(x) 値xの個数を返す list.count(5)
sort() ソート(破壊的) list.sort()
reverse() 逆順(破壊的) list.reverse()
copy() コピーを作成 new = list.copy()
clear() 全要素を削除 list.clear()

リストの結合

list1 = [1, 2, 3]
list2 = [4, 5, 6]

# + で結合
combined = list1 + list2  # [1, 2, 3, 4, 5, 6]

# extend で追加
list1.extend(list2)  # list1が [1, 2, 3, 4, 5, 6] になる

# * で繰り返し
repeated = [0] * 5  # [0, 0, 0, 0, 0]

リストのソート

numbers = [3, 1, 4, 1, 5, 9, 2, 6]

# sort(): 元のリストを変更
numbers.sort()
print(numbers)  # [1, 1, 2, 3, 4, 5, 6, 9]

numbers.sort(reverse=True)
print(numbers)  # [9, 6, 5, 4, 3, 2, 1, 1]

# sorted(): 新しいリストを返す
original = [3, 1, 4, 1, 5]
sorted_list = sorted(original)
print(original)     # [3, 1, 4, 1, 5](変更なし)
print(sorted_list)  # [1, 1, 3, 4, 5]

タプル(tuple)

タプルはリストに似ていますが、作成後に変更できない(イミュータブル)点が異なります。

# タプルの作成
coordinates = (10, 20)
rgb = (255, 128, 0)
single = (42,)  # 要素が1つの場合はカンマが必要

# アクセス(リストと同じ)
print(coordinates[0])  # 10
print(rgb[1:])         # (128, 0)

# 変更はできない
# coordinates[0] = 5  # TypeError!

タプルのアンパック

# 複数の変数に一度に代入
point = (3, 4)
x, y = point
print(x)  # 3
print(y)  # 4

# 関数から複数の値を返す
def get_min_max(numbers):
    return min(numbers), max(numbers)

minimum, maximum = get_min_max([3, 1, 4, 1, 5])
print(minimum, maximum)  # 1 5

# 変数の入れ替え
a, b = 1, 2
a, b = b, a
print(a, b)  # 2 1

タプル vs リスト

特性 タプル リスト
変更可能 ❌ ✅
括弧 () []
用途 固定データ 可変データ
辞書のキー 使える 使えない
処理速度 速い 遅い

辞書(dict)

辞書は、キーと値のペアでデータを管理します。

flowchart TB
    subgraph Dict["辞書 person"]
        K1["'name'"] --> V1["'Taro'"]
        K2["'age'"] --> V2["25"]
        K3["'city'"] --> V3["'Tokyo'"]
    end

    style Dict fill:#3b82f6,color:#fff
    style K1 fill:#8b5cf6,color:#fff
    style K2 fill:#8b5cf6,color:#fff
    style K3 fill:#8b5cf6,color:#fff
    style V1 fill:#22c55e,color:#fff
    style V2 fill:#22c55e,color:#fff
    style V3 fill:#22c55e,color:#fff

辞書の作成

# 空の辞書
empty = {}
also_empty = dict()

# 値を持つ辞書
person = {
    "name": "Taro",
    "age": 25,
    "city": "Tokyo"
}

# dict()を使用
person = dict(name="Taro", age=25, city="Tokyo")

値へのアクセス

person = {"name": "Taro", "age": 25, "city": "Tokyo"}

# キーでアクセス
print(person["name"])  # Taro

# get()を使用(キーがない場合にエラーにならない)
print(person.get("name"))      # Taro
print(person.get("country"))   # None
print(person.get("country", "Japan"))  # Japan(デフォルト値)

辞書の変更

person = {"name": "Taro", "age": 25}

# 値の更新
person["age"] = 26

# 新しいキーの追加
person["city"] = "Tokyo"

# 複数の更新
person.update({"age": 27, "job": "Engineer"})

# キーの削除
del person["city"]
removed = person.pop("age")  # 値を取得して削除

辞書のメソッド

メソッド 説明 例
get(key, default) 値を取得 d.get("name", "Unknown")
keys() キーの一覧 d.keys()
values() 値の一覧 d.values()
items() キーと値のペア d.items()
pop(key) キーを削除して値を返す d.pop("name")
update(dict) 辞書を更新 d.update({"a": 1})
clear() 全要素を削除 d.clear()

辞書のループ

person = {"name": "Taro", "age": 25, "city": "Tokyo"}

# キーでループ
for key in person:
    print(key)

# 値でループ
for value in person.values():
    print(value)

# キーと値でループ
for key, value in person.items():
    print(f"{key}: {value}")

辞書のキーの確認

person = {"name": "Taro", "age": 25}

if "name" in person:
    print("nameキーがあります")

if "country" not in person:
    print("countryキーはありません")

セット(set)

セットは、重複のない値のコレクションです。

flowchart TB
    subgraph Set["セット numbers"]
        A["1"]
        B["2"]
        C["3"]
        D["4"]
        E["5"]
    end

    style Set fill:#3b82f6,color:#fff

セットの作成

# 空のセット
empty = set()  # {} は空の辞書になるので注意

# 値を持つセット
numbers = {1, 2, 3, 4, 5}
fruits = {"apple", "banana", "cherry"}

# リストからセットを作成(重複が除去される)
numbers = set([1, 2, 2, 3, 3, 3])
print(numbers)  # {1, 2, 3}

セットの操作

numbers = {1, 2, 3}

# 追加
numbers.add(4)
print(numbers)  # {1, 2, 3, 4}

# 削除
numbers.remove(2)     # 存在しないとエラー
numbers.discard(10)   # 存在しなくてもエラーにならない

# 存在確認
print(3 in numbers)  # True

セットの集合演算

a = {1, 2, 3, 4}
b = {3, 4, 5, 6}

# 和集合(どちらかに含まれる)
print(a | b)  # {1, 2, 3, 4, 5, 6}
print(a.union(b))

# 積集合(両方に含まれる)
print(a & b)  # {3, 4}
print(a.intersection(b))

# 差集合(aにあってbにない)
print(a - b)  # {1, 2}
print(a.difference(b))

# 対称差(どちらか一方にのみ含まれる)
print(a ^ b)  # {1, 2, 5, 6}
print(a.symmetric_difference(b))
flowchart LR
    subgraph Union["和集合 a | b"]
        U1["1, 2, 3, 4, 5, 6"]
    end

    subgraph Intersection["積集合 a & b"]
        I1["3, 4"]
    end

    subgraph Difference["差集合 a - b"]
        D1["1, 2"]
    end

    style Union fill:#3b82f6,color:#fff
    style Intersection fill:#22c55e,color:#fff
    style Difference fill:#f59e0b,color:#fff

リスト内包表記

リストを簡潔に作成する方法です。

基本形

# 従来の方法
squares = []
for x in range(5):
    squares.append(x ** 2)
print(squares)  # [0, 1, 4, 9, 16]

# リスト内包表記
squares = [x ** 2 for x in range(5)]
print(squares)  # [0, 1, 4, 9, 16]

条件付き

# 偶数のみの2乗
even_squares = [x ** 2 for x in range(10) if x % 2 == 0]
print(even_squares)  # [0, 4, 16, 36, 64]

# if-elseを使う場合
results = ["even" if x % 2 == 0 else "odd" for x in range(5)]
print(results)  # ['even', 'odd', 'even', 'odd', 'even']

ネストしたループ

# 九九の組み合わせ
pairs = [(i, j) for i in range(1, 4) for j in range(1, 4)]
print(pairs)
# [(1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (2, 3), (3, 1), (3, 2), (3, 3)]

辞書内包表記

# 数値をキーに、その2乗を値とする辞書
squares = {x: x ** 2 for x in range(5)}
print(squares)  # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

セット内包表記

# 2乗の値のセット
squares = {x ** 2 for x in range(-3, 4)}
print(squares)  # {0, 1, 4, 9}(重複が除去される)

まとめ

データ構造 括弧 特徴 用途
list [] 順序あり、変更可能 汎用的なコレクション
tuple () 順序あり、変更不可 固定データ、辞書のキー
dict {} キーと値のペア 名前付きデータ
set {} 重複なし、順序なし 重複除去、集合演算

重要ポイント

  1. リストは最も汎用的で、追加・削除・変更が自由
  2. タプルは変更不可だが、辞書のキーに使える
  3. 辞書はキーで値にアクセスする(O(1)で高速)
  4. セットは重複を自動的に除去し、集合演算が可能
  5. 内包表記を使うとコードが簡潔になる

練習問題

問題1: リスト操作

1から10までの数値のリストを作成し、偶数だけを取り出した新しいリストを作成してください。

問題2: 辞書

5人の名前と年齢を格納した辞書を作成し、全員の平均年齢を計算して表示してください。

チャレンジ問題

2つのリストの共通要素と、どちらか一方にしかない要素を見つけるプログラムを、セットを使って書いてください。

list1 = [1, 2, 3, 4, 5]
list2 = [4, 5, 6, 7, 8]
# 共通: [4, 5]
# list1のみ: [1, 2, 3]
# list2のみ: [6, 7, 8]

参考リンク


次回予告: Day 5では「関数」について学びます。コードを再利用可能な部品として整理しましょう!