Pythonのデータ構造を学ぼう!
クルミとジャービスのPython冒険記 - データ構造編
クルミ: ジャービス、前回は Python の基本を学んだけど、今日はどんなことを勉強するの?
ジャービス: 今日は Python のデータ構造について学びましょう!データ構造は、データを効率的に格納・操作するための方法です。Python には強力な組み込みデータ構造があり、これらを使いこなせるようになると、プログラミングがもっと楽しくなりますよ。
クルミ: データ構造って聞くと難しそう...でも頑張るよ!どんな種類があるの?
ジャービス: 主に4つの基本的なデータ構造があります:リスト、タプル、集合、辞書です。それぞれ特徴が異なるので、用途に応じて使い分けることが大切です。まずはリストから見ていきましょう。
リスト (Lists)
ジャービス: リストは順序付けられた変更可能なデータのコレクションです。角括弧 []
で作成します。
# リストの作成
fish_types = ["マグロ", "サケ", "タイ", "フグ"]
print(fish_types) # ['マグロ', 'サケ', 'タイ', 'フグ']
クルミ: なるほど!魚の名前をリストにしたんだね。でも、リストには魚の名前だけじゃなくて、他の種類のデータも入れられるの?
ジャービス: もちろんです!リストには異なる型のデータを混ぜて格納することができます。
mixed_list = ["マグロ", 3, 25.5, True]
print(mixed_list) # ['マグロ', 3, 25.5, True]
クルミ: すごい!文字列、整数、小数、真偽値が一つのリストに入ってる!でも、リストの中の特定の要素を取り出すにはどうするの?
ジャービス: インデックスを使って要素にアクセスします。Python のインデックスは0から始まることを覚えておいてください。
fish_types = ["マグロ", "サケ", "タイ", "フグ"]
print(fish_types[0]) # 'マグロ'
print(fish_types[2]) # 'タイ'
クルミ: 0から始まるんだね、覚えておくよ。あと、リストの最後の要素を取り出すときはどうするの?
ジャービス: 負のインデックスを使うと、リストの末尾から要素にアクセスできます。-1が最後の要素、-2が最後から2番目の要素という具合です。
fish_types = ["マグロ", "サケ", "タイ", "フグ"]
print(fish_types[-1]) # 'フグ'
print(fish_types[-2]) # 'タイ'
クルミ: 便利だね!リストを変更することもできるの?
ジャービス: はい、リストは変更可能(ミュータブル)なので、要素の追加、削除、変更ができます。
fish_types = ["マグロ", "サケ", "タイ", "フグ"]
# 要素の変更
fish_types[1] = "カツオ"
print(fish_types) # ['マグロ', 'カツオ', 'タイ', 'フグ']
# 要素の追加
fish_types.append("サバ")
print(fish_types) # ['マグロ', 'カツオ', 'タイ', 'フグ', 'サバ']
# 特定の位置に挿入
fish_types.insert(2, "イワシ")
print(fish_types) # ['マグロ', 'カツオ', 'イワシ', 'タイ', 'フグ', 'サバ']
# 要素の削除
fish_types.remove("タイ")
print(fish_types) # ['マグロ', 'カツオ', 'イワシ', 'フグ', 'サバ']
クルミ: わかりやすい!リストは本当に便利だね。他にも便利な機能はある?
ジャービス: リストのスライスという機能もあります。これを使うと、リストの一部を取り出すことができます。
fish_types = ["マグロ", "サケ", "タイ", "フグ", "サバ", "イワシ"]
# スライス [開始:終了:ステップ]
print(fish_types[1:4]) # ['サケ', 'タイ', 'フグ']
print(fish_types[:3]) # ['マグロ', 'サケ', 'タイ']
print(fish_types[3:]) # ['フグ', 'サバ', 'イワシ']
print(fish_types[::2]) # ['マグロ', 'タイ', 'サバ']
クルミ: スライスもすごく便利!特に ::2
で1つおきに取り出せるのが面白いね。
ジャービス: そうですね。また、リストの内包表記という機能もあります。これを使うと、既存のリストから新しいリストを簡潔に作成できます。
# 基本的な内包表記
squares = [x**2 for x in range(10)]
print(squares) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
# 条件付き内包表記
even_squares = [x**2 for x in range(10) if x % 2 == 0]
print(even_squares) # [0, 4, 16, 36, 64]
# 魚の例
fish_lengths = [15, 25, 10, 30, 20]
big_fish = [length for length in fish_lengths if length > 20]
print(big_fish) # [25, 30]
クルミ: 内包表記はちょっと複雑に見えるけど、すごく便利そう!一行でたくさんのことができるんだね。
タプル (Tuples)
ジャービス: 次はタプルについて見ていきましょう。タプルはリストと似ていますが、作成後に変更することができません(イミュータブル)。丸括弧 ()
で作成します。
# タプルの作成
fish_data = ("マグロ", 25.5, 3)
print(fish_data) # ('マグロ', 25.5, 3)
# 単一要素のタプル(カンマが必要)
single_item_tuple = ("コイ",)
print(single_item_tuple) # ('コイ',)
クルミ: タプルはリストと似てるけど、変更できないんだね。でも、なぜ変更できないタプルが必要なの?
ジャービス: 良い質問です!タプルは変更できないため、データの安全性が保証されます。また、タプルはハッシュ可能なので、辞書のキーとして使用できます。さらに、タプルは通常、異なる型の関連データを格納するために使用されます。
# 関数から複数の値を返す
def get_fish_stats():
return "マグロ", 25.5, 3 # これは暗黙的にタプルを返します
name, length, age = get_fish_stats()
print(f"{name}は{age}歳で、長さは{length}cmです。") # マグロは3歳で、長さは25.5cmです。
クルミ: なるほど!複数の値を一度に返せるのは便利だね。タプルのアンパックって何?
ジャービス: タプルのアンパックとは、タプルの要素を個別の変数に分解することです。先ほどの例でも使いましたが、もう少し詳しく見てみましょう。
fish_data = ("マグロ", 25.5, 3)
# タプルのアンパック
name, length, age = fish_data
print(name) # 'マグロ'
print(length) # 25.5
print(age) # 3
# 一部の要素を無視
name, _, _ = fish_data
print(name) # 'マグロ'
# 残りの要素をリストとして取得
first, *rest = fish_data
print(first) # 'マグロ'
print(rest) # [25.5, 3]
クルミ: アンパックは本当に便利だね!特に *rest
の使い方が面白いよ。
集合 (Sets)
ジャービス: 次は集合について見ていきましょう。集合は順序なしの一意な要素のコレクションです。重複を許さず、数学的な集合演算をサポートしています。中括弧 {}
で作成します。
# 集合の作成
fish_types = {"マグロ", "サケ", "タイ", "フグ", "マグロ"}
print(fish_types) # {'マグロ', 'サケ', 'タイ', 'フグ'} (重複は自動的に削除)
# 空の集合
empty_set = set() # 注意: {} は空の辞書を作成する
クルミ: 集合は重複を自動的に削除するんだね!他にどんな特徴があるの?
ジャービス: 集合の最も強力な機能は、数学的な集合演算をサポートしていることです。和集合、積集合、差集合などの操作が簡単にできます。
freshwater_fish = {"コイ", "フナ", "ウナギ", "アユ"}
saltwater_fish = {"マグロ", "サケ", "タイ", "フグ", "ウナギ"}
# 和集合 (Union)
all_fish = freshwater_fish | saltwater_fish
print(all_fish) # {'コイ', 'フナ', 'ウナギ', 'アユ', 'マグロ', 'サケ', 'タイ', 'フグ'}
# 積集合 (Intersection)
common_fish = freshwater_fish & saltwater_fish
print(common_fish) # {'ウナギ'}
# 差集合 (Difference)
only_freshwater = freshwater_fish - saltwater_fish
print(only_freshwater) # {'コイ', 'フナ', 'アユ'}
クルミ: すごい!数学の集合と同じように使えるんだね。これは便利そう!
ジャービス: そうですね。集合は重複を削除したり、共通の要素を見つけたりするのに最適です。また、メンバーシップテスト(要素が含まれているかの確認)も高速です。
# メンバーシップテスト
print("マグロ" in saltwater_fish) # True
print("コイ" in saltwater_fish) # False
クルミ: 集合は特定の要素が含まれているかを素早く確認できるんだね。これは検索に便利そう!
辞書 (Dictionaries)
ジャービス: 最後に辞書について見ていきましょう。辞書はキーと値のペアのコレクションです。各キーは一意で、値にマッピングされています。中括弧 {}
とコロン :
で作成します。
# 辞書の作成
fish_info = {
"name": "マグロ",
"weight": 80.5,
"length": 150,
"is_fresh": True
}
print(fish_info) # {'name': 'マグロ', 'weight': 80.5, 'length': 150, 'is_fresh': True}
クルミ: 辞書は実際の辞書みたいに、キーワード(キー)から情報(値)を探せるんだね!どうやって値にアクセスするの?
ジャービス: キーを使って値にアクセスします。
# 値へのアクセス
print(fish_info["name"]) # 'マグロ'
print(fish_info["weight"]) # 80.5
# get() メソッドを使用(キーが存在しない場合はデフォルト値を返す)
print(fish_info.get("color", "不明")) # '不明'
クルミ: get()
メソッドは便利だね!キーが存在しない場合にエラーを避けられるんだね。辞書も変更できるの?
ジャービス: はい、辞書は変更可能です。キーと値のペアの追加、削除、更新ができます。
fish_info = {"name": "マグロ", "weight": 80.5}
# 項目の追加/更新
fish_info["length"] = 150
fish_info["weight"] = 85.2
print(fish_info) # {'name': 'マグロ', 'weight': 85.2, 'length': 150}
# 項目の削除
del fish_info["weight"]
print(fish_info) # {'name': 'マグロ', 'length': 150}
クルミ: 辞書も便利だね!辞書のループ処理はどうするの?
ジャービス: 辞書のループ処理には、keys()
、values()
、items()
メソッドが便利です。
fish_info = {
"name": "マグロ",
"weight": 80.5,
"length": 150,
"is_fresh": True
}
# キーでループ
for key in fish_info:
print(key, fish_info[key])
# items() メソッドを使用
for key, value in fish_info.items():
print(key, value)
クルミ: なるほど!items()
を使うと、キーと値の両方に一度にアクセスできるんだね。
ジャービス: そうです。また、辞書の内包表記も使えます。これを使うと、既存の辞書から新しい辞書を簡潔に作成できます。
# 辞書の内包表記
fish_lengths = {"マグロ": 150, "サケ": 80, "タイ": 40, "フグ": 30, "サバ": 60}
big_fish = {name: length for name, length in fish_lengths.items() if length > 50}
print(big_fish) # {'マグロ': 150, 'サケ': 80, 'サバ': 60}
ネストしたデータ構造
クルミ: これまでの4つのデータ構造、すごく便利だね!でも、もっと複雑なデータを扱いたい場合はどうするの?
ジャービス: 良い質問です!Python のデータ構造は互いにネストさせることができます。これにより、複雑なデータモデルを作成することができます。
# 魚市場のデータ
fish_market = {
"name": "築地市場",
"location": "東京",
"sections": [
{
"name": "マグロ専門",
"inventory": [
{"name": "クロマグロ", "price": 12000, "stock": 3},
{"name": "メバチマグロ", "price": 8000, "stock": 5}
]
},
{
"name": "白身魚",
"inventory": [
{"name": "タイ", "price": 4000, "stock": 10},
{"name": "ヒラメ", "price": 5000, "stock": 8}
]
}
]
}
# アクセス例
print(fish_market["name"]) # '築地市場'
print(fish_market["sections"][0]["name"]) # 'マグロ専門'
print(fish_market["sections"][1]["inventory"][0]["name"]) # 'タイ'
クルミ: すごい!辞書の中にリストがあって、そのリストの中に辞書があるんだね。これで複雑なデータも扱えそう!
データ構造の選択
クルミ: 4つのデータ構造を学んだけど、どれを使えばいいか迷うことがありそう...どうやって選べばいいの?
ジャービス: データ構造の選択は、データの性質と必要な操作によって決まります。簡単なガイドラインを紹介しましょう:
-
リスト:順序が重要で、要素が変更される可能性がある場合
- 例:魚の名前のリスト、釣った魚の記録
-
タプル:順序が重要で、要素が変更されない場合
- 例:魚の座標 (x, y, z)、RGB色値
-
集合:順序が重要でなく、重複を許さない場合
- 例:釣った魚の種類(重複なし)、共通の魚を見つける
-
辞書:キーと値のマッピングが必要な場合
- 例:魚の詳細情報、在庫管理
クルミ: わかりやすい説明ありがとう!これで適切なデータ構造を選べそうだよ。
まとめ
ジャービス: 今日は Python の主要なデータ構造について学びました。リスト、タプル、集合、辞書はそれぞれ異なる特徴を持ち、適切に使い分けることが重要です。
クルミ: 今日学んだことをまとめると:
-
リスト:順序付けられた変更可能なコレクション
[1, 2, 3]
-
タプル:順序付けられた変更不可能なコレクション
(1, 2, 3)
-
集合:順序なしの一意な要素のコレクション
{1, 2, 3}
-
辞書:キーと値のペアのコレクション
{"a": 1, "b": 2}
ジャービス: 素晴らしいまとめです!これらのデータ構造を使いこなせるようになると、Python プログラミングがもっと楽しくなりますよ。
クルミ: 次回は何を学ぶの?
ジャービス: 次回は関数とモジュールについて学びます。これらを使うと、コードをより整理された再利用可能な形で書くことができます。
クルミ: 楽しみにしてるよ!今日はありがとう、ジャービス!
練習問題
- 5種類の日本の魚のリストを作成し、アルファベット順にソートしてください。
- 魚の名前と価格のタプルのリストを作成し、価格が高い順にソートしてください。
- 淡水魚と海水魚の集合を作成し、両方に生息できる魚を見つけてください。
- 魚の名前をキー、その特性(価格、重さ、原産地など)を値とする辞書を作成してください。
- 魚市場のデータ構造を作成し、特定のセクションの在庫を表示する関数を作成してください。
次回もお楽しみに!