文字列とコンテナの総合演習
これまでのレッスンでは、リスト、タプル、辞書、セット、文字列メソッドを学びました。今回はそれらを組み合わせて、最も一般的な「コンボ」を使って実際の問題を解決します。これらのテクニックはプロフェッショナルなプログラミングで日常的に使われています。
1. split() とリストの連携
split() は文字列をリストに分解します——データ処理の第一歩です:
# CSV データの解析
line = "Alice,25,Beijing,Engineer"
fields = line.split(",")
print(fields) # ['Alice', '25', 'Beijing', 'Engineer']
# 空白による分割(デフォルト)
text = "hello world python"
words = text.split()
print(words) # ['hello', 'world', 'python']
# 分割数の制限
data = "2026-06-23-15-30-00"
parts = data.split("-", 3)
print(parts) # ['2026', '06', '23', '15-30-00']
例:設定ファイルの解析(難易度 ⭐⭐)
# 設定ファイルの解析をシミュレート
config_text = """
host=localhost
port=8080
debug=true
theme=dark
"""
# 行で分割 → 等号で分割 → 辞書に保存
config = {}
for line in config_text.strip().split("\n"):
if "=" in line:
key, value = line.split("=", 1)
config[key.strip()] = value.strip()
print(config)
# {'host': 'localhost', 'port': '8080', 'debug': 'true', 'theme': 'dark'}
# 設定を読み取り
print(f"Current host: {config.get('host', 'localhost')}")
print(f"Current port: {config.get('port', '80')}")
出力:
{'host': 'localhost', 'port': '8080', 'debug': 'true', 'theme': 'dark'}
Current host: localhost
Current port: 8080
2. join() の威力
join() は split() の逆で——リストを文字列に結合します:
# 基本的な使い方
words = ["Hello", "World", "Python"]
sentence = " ".join(words)
print(sentence) # Hello World Python
# カンマで結合
csv = ",".join(["Alice", "25", "Beijing"])
print(csv) # Alice,25,Beijing
# 改行で結合
lines = "\n".join(["First line", "Second line", "Third line"])
print(lines)
join() のパフォーマンス上の利点
# ❌ 推奨しない — ループ内での文字列連結
result = ""
for i in range(1000):
result += str(i) + ","
# これにより 1000 個の一時的な文字列オブジェクトが作成される
# ✅ 推奨 — リストに集めて join()
parts = [str(i) for i in range(1000)]
result = ",".join(parts)
# 1 回のマージで、はるかに効率的
例:表の書式設定(難易度 ⭐⭐)
# join + リスト内包表記でフォーマット済み表出力
headers = ["Name", "Age", "City"]
rows = [
["Alice", "25", "Beijing"],
["Bob", "30", "Shanghai"],
["Charlie", "22", "Guangzhou"],
]
# ヘッダー
print(" | ".join(headers))
print("-" * 25)
# データ行
for row in rows:
print(" | ".join(row))
出力:
Name | Age | City
─────────────────────────
Alice | 25 | Beijing
Bob | 30 | Shanghai
Charlie | 22 | Guangzhou
3. sorted() と文字列・辞書
sorted() はリストだけでなく、任意の反復可能オブジェクトに対して機能します:
# 文字列のソート — アルファベット順
text = "python"
sorted_chars = sorted(text)
print(sorted_chars) # ['h', 'n', 'o', 'p', 't', 'y']
print("".join(sorted_chars)) # hnopty — 再結合
# 辞書のソート — デフォルトでキーをソート
d = {"banana": 3, "apple": 5, "cherry": 2}
sorted_keys = sorted(d)
print(sorted_keys) # ['apple', 'banana', 'cherry']
# 値でソート
sorted_by_value = sorted(d.items(), key=lambda x: x[1])
print(sorted_by_value) # [('cherry', 2), ('banana', 3), ('apple', 5)]
# セットのソート
s = {3, 1, 4, 1, 5, 9}
sorted_set = sorted(s)
print(sorted_set) # [1, 3, 4, 5, 9]
例:カスタムソートルール(難易度 ⭐⭐)
# ファイル名を数値部分でソート
files = ["file_10.txt", "file_2.txt", "file_1.txt", "file_20.txt"]
# 通常のソート — 文字列ソート、「10」は「2」より前に来る('1' < '2' のため)
print(sorted(files))
# ['file_1.txt', 'file_10.txt', 'file_2.txt', 'file_20.txt']
# 数値部分でソート — 数値を抽出し int に変換してからソート
def extract_number(filename):
num_str = filename.split("_")[1].split(".")[0]
return int(num_str)
sorted_files = sorted(files, key=extract_number)
print(sorted_files)
# ['file_1.txt', 'file_2.txt', 'file_10.txt', 'file_20.txt']
4. enumerate() と zip()
この 2 つの組み込み関数は日常業務で非常に一般的です。
enumerate() — 反復中にインデックスを取得
fruits = ["apple", "banana", "orange"]
# enumerate なし — 不格好
for i in range(len(fruits)):
print(f"{i + 1}. {fruits[i]}")
# enumerate あり — エレガント
for i, fruit in enumerate(fruits, 1): # start=1 で 1 からカウント
print(f"{i}. {fruit}")
zip() — 複数リストの並列反復
names = ["Alice", "Bob", "Charlie"]
scores = [85, 92, 78]
cities = ["Beijing", "Shanghai", "Guangzhou"]
# 3 つのリストを同時に反復
for name, score, city in zip(names, scores, cities):
print(f"{name}: {score} points, from {city}")
出力:
Alice: 85 points, from Beijing
Bob: 92 points, from Shanghai
Charlie: 78 points, from Guangzhou
例:学生スコアレポート(難易度 ⭐⭐⭐)
# enumerate + zip を使って完全なレポートカードを生成
students = ["Alice", "Bob", "Charlie", "Diana"]
chinese = [85, 92, 78, 88]
math = [90, 85, 95, 80]
english = [78, 95, 82, 90]
print("=== Student Score Report ===")
print(f"{'Rank':<4}{'Name':<8}{'Chinese':<8}{'Math':<8}{'English':<8}{'Average':<8}")
# 平均を計算
averages = [(c + m + e) / 3 for c, m, e in zip(chinese, math, english)]
# 平均の降順でソート
data = list(zip(students, chinese, math, english, averages))
data.sort(key=lambda x: x[4], reverse=True)
# 出力
for rank, (name, c, m, e, avg) in enumerate(data, 1):
print(f"{rank:<4}{name:<8}{c:<8}{m:<8}{e:<8}{avg:<8.1f}")
5. 総合データ処理ケース
学んだすべてを実際のシナリオに適用しましょう:
ケース:ログ分析(難易度 ⭐⭐⭐)
# シミュレートされたサーバーログ
log_data = """
2026-06-20 10:23:45 INFO User 1001 logged in
2026-06-20 10:25:12 ERROR Database connection timeout
2026-06-20 10:26:30 INFO User 1002 logged in
2026-06-20 10:27:45 WARN Disk usage 85%
2026-06-20 10:28:10 ERROR User 1001 request timeout
2026-06-20 10:29:00 INFO User 1001 logged out
"""
# 1. 行で分割
lines = log_data.strip().split("\n")
# 2. 各ログエントリを解析
parsed = []
for line in lines:
parts = line.split()
timestamp = f"{parts[0]} {parts[1]}"
level = parts[2]
message = " ".join(parts[3:])
parsed.append({"time": timestamp, "level": level, "msg": message})
# 3. レベル別にカウント
level_count = {}
for entry in parsed:
level = entry["level"]
level_count[level] = level_count.get(level, 0) + 1
# 4. レベル順にソートして出力
print("=== Log Statistics ===")
for level, count in sorted(level_count.items()):
print(f"{level}: {count} entries")
# 5. すべての ERROR を抽出
print("\n=== Error Details ===")
errors = [e for e in parsed if e["level"] == "ERROR"]
for e in errors:
print(f"[{e['time']}] {e['msg']}")
出力:
=== Log Statistics ===
ERROR: 2 entries
INFO: 3 entries
WARN: 1 entry
=== Error Details ===
[2026-06-20 10:25:12] Database connection timeout
[2026-06-20 10:28:10] User 1001 request timeout
よくあるユースケース
- 設定解析:
split()で区切り文字分割 → 辞書に保存 - データエクスポート:リスト内包表記 +
join()で CSV や表形式にデータをフォーマット - ログ分析:行で分割 → フィールド解析 → 辞書に保存 →
sorted()と内包表記で統計 - 複数テーブル結合:
zip()で複数のデータリストを並列反復して完全なレコードに - ランキング:
enumerate(sorted(...))で番号付きソート結果を生成
❓ よくある質問
split() と split(" ") の違いは何ですか?split() は任意の空白(スペース、改行、タブ)で分割し、空の文字列を自動的に削除します。split(" ") は単一スペースでのみ分割し、連続するスペースは空の文字列を生成します。ほとんどの場合、引数なしの split() が良い選択です。join() はリスト内のすべての要素が文字列である必要がありますか?
A:はい。",".join([1, 2, 3]) はエラーになります。数値を先に文字列に変換してください:",".join(str(x) for x in [1, 2, 3])、またはリスト内包表記で str() を使います。
zip() が異なる長さのリストを処理するときはどうなりますか?zip() は最も短いリストで停止します。3 つのリストのうち 1 つが 2 要素しかない場合、zip() は 2 組しか生成しません。最も長いリストに合わせて None で埋めるには、itertools.zip_longest() を使用します。📖 まとめ
split()は文字列をリストに分解。引数なしでは空白で分割し、空要素を自動削除join()はリストを文字列に結合。文字列連結の推奨方法(+=より効率的)sorted()は任意の反復可能オブジェクト(文字列、辞書、セット)に使用可能enumerate()は反復中にインデックスを取得。startパラメータで開始値を指定zip()は複数リストを並列反復。関連データのマージに最適- これらのツールを組み合わせることで、効率的な実世界のデータ処理が可能に
📝 練習問題
-
基本(難易度 ⭐):
s = "apple,banana,orange,grape"として、split()でリストに分解し、join()で"apple | banana | orange | grape"を出力してください。 -
中級(難易度 ⭐⭐):2 つのリスト
students = ["Alice", "Bob", "Charlie"]とscores = [85, 92, 78]が与えられたとき、zip()とenumerate()を使ってランキングレポートを出力してください:TEXT#1: Bob — 92 points #2: Alice — 85 points #3: Charlie — 78 points -
挑戦(難易度 ⭐⭐⭐):「簡易 CSV ジェネレーター」を書いてください。リストのリスト
data = [["Name", "Age", "City"], ["Alice", 25, "Beijing"], ["Bob", 30, "Shanghai"]]が与えられたとき、CSV 文字列(カンマ区切りの行)として出力します。ヒント:数値にはリスト内包表記でstr()を使い、各行に",".join()、全行に"\n".join()を使用。



