Python辞書のキーと値を入れ替える方法完全ガイド:効率的な反転・スワップテクニック
Python辞書で「キーと値を逆にしたい」「逆引き辞書を作成したい」という場面は多くあります。データの変換、検索の高速化、APIレスポンスの整形など、様々な用途で辞書の反転が必要になります。本記事では、辞書のキーと値を効率的に入れ替える方法を、実践的なサンプルコードとともに詳しく解説します。
基本的なキーと値の入れ替え方法
辞書内包表記を使った基本的な反転
最もシンプルで読みやすい方法です。
original = {'a': 1, 'b': 2, 'c': 3}
# キーと値を入れ替え
reversed_dict = {v: k for k, v in original.items()}
print(reversed_dict) # {1: 'a', 2: 'b', 3: 'c'}
for文を使った反転
original = {'name': '太郎', 'age': 25, 'city': '東京'}
# for文で反転
reversed_dict = {}
for key, value in original.items():
reversed_dict[value] = key
print(reversed_dict) # {'太郎': 'name', 25: 'age', '東京': 'city'}
dict()コンストラクタを使用
original = {'apple': 'りんご', 'banana': 'バナナ', 'orange': 'オレンジ'}
# dict()を使用した反転
reversed_dict = dict((v, k) for k, v in original.items())
print(reversed_dict) # {'りんご': 'apple', 'バナナ': 'banana', 'オレンジ': 'orange'}
値が重複する場合の処理
値の重複を無視する方法
colors = {'red': '赤', 'blue': '青', 'green': '緑', 'crimson': '赤'}
# 後から処理されたキーで上書き
simple_reverse = {v: k for k, v in colors.items()}
print(simple_reverse) # {'赤': 'crimson', '青': 'blue', '緑': 'green'}
重複する値をリストで保持
colors = {'red': '赤', 'blue': '青', 'green': '緑', 'crimson': '赤'}
# 重複値はリストで管理
def reverse_with_duplicates(dictionary):
reversed_dict = {}
for key, value in dictionary.items():
if value not in reversed_dict:
reversed_dict[value] = []
reversed_dict[value].append(key)
return reversed_dict
result = reverse_with_duplicates(colors)
print(result) # {'赤': ['red', 'crimson'], '青': ['blue'], '緑': ['green']}
最初に見つかった値のみ保持
colors = {'red': '赤', 'blue': '青', 'green': '緑', 'crimson': '赤'}
# 最初の値のみ保持
def reverse_first_only(dictionary):
reversed_dict = {}
for key, value in dictionary.items():
if value not in reversed_dict:
reversed_dict[value] = key
return reversed_dict
result = reverse_first_only(colors)
print(result) # {'赤': 'red', '青': 'blue', '緑': 'green'}
特定の型の値のみ反転
数値のみを反転
mixed_data = {'name': '太郎', 'age': 25, 'score': 85, 'active': True}
# 数値のみ反転
numeric_reverse = {
v: k for k, v in mixed_data.items()
if isinstance(v, (int, float))
}
print(numeric_reverse) # {25: 'age', 85: 'score'}
文字列のみを反転
user_info = {'id': 123, 'name': '太郎', 'email': 'taro@example.com', 'age': 25}
# 文字列のみ反転
string_reverse = {
v: k for k, v in user_info.items()
if isinstance(v, str)
}
print(string_reverse) # {'太郎': 'name', 'taro@example.com': 'email'}
条件付き反転
scores = {'太郎': 85, '花子': 92, '次郎': 76, '美香': 89}
# 80点以上のみ反転
high_scores_reverse = {
v: k for k, v in scores.items()
if v >= 80
}
print(high_scores_reverse) # {85: '太郎', 92: '花子', 89: '美香'}
実践的な応用例
エラーコード辞書の反転
error_codes = {
'NOT_FOUND': 404,
'UNAUTHORIZED': 401,
'FORBIDDEN': 403,
'SERVER_ERROR': 500
}
# エラーコードからメッセージを検索するため反転
code_to_message = {v: k for k, v in error_codes.items()}
print(code_to_message) # {404: 'NOT_FOUND', 401: 'UNAUTHORIZED', 403: 'FORBIDDEN', 500: 'SERVER_ERROR'}
# 使用例
def get_error_message(code):
return code_to_message.get(code, 'UNKNOWN_ERROR')
print(get_error_message(404)) # 'NOT_FOUND'
商品IDと名前の相互変換
products = {
'PROD001': 'ノートPC',
'PROD002': 'マウス',
'PROD003': 'キーボード',
'PROD004': 'モニター'
}
# 商品名からIDを検索するため反転
name_to_id = {v: k for k, v in products.items()}
def find_product_id(product_name):
return name_to_id.get(product_name, 'NOT_FOUND')
def find_product_name(product_id):
return products.get(product_id, 'NOT_FOUND')
print(find_product_id('マウス')) # 'PROD002'
print(find_product_name('PROD003')) # 'キーボード'
多言語対応での活用
japanese_to_english = {
'犬': 'dog',
'猫': 'cat',
'鳥': 'bird',
'魚': 'fish'
}
# 英語から日本語への変換辞書を作成
english_to_japanese = {v: k for k, v in japanese_to_english.items()}
def translate_to_english(japanese_word):
return japanese_to_english.get(japanese_word, '翻訳不可')
def translate_to_japanese(english_word):
return english_to_japanese.get(english_word, '翻訳不可')
print(translate_to_english('猫')) # 'cat'
print(translate_to_japanese('dog')) # '犬'
ネストした辞書での反転
単階層の値のみ反転
user_data = {
'personal': {'name': '太郎', 'age': 25},
'contact': {'email': 'taro@example.com', 'phone': '090-1234-5678'}
}
# トップレベルキーのみ反転
top_level_reverse = {str(v): k for k, v in user_data.items()}
print(top_level_reverse) # 辞書オブジェクトが文字列化されて表示
ネストした辞書を平坦化して反転
nested_config = {
'database': {
'host': 'localhost',
'port': 5432
},
'cache': {
'host': 'redis-server',
'port': 6379
}
}
def flatten_and_reverse(nested_dict, parent_key='', sep='_'):
"""ネストした辞書を平坦化して反転"""
flattened = {}
for key, value in nested_dict.items():
new_key = f"{parent_key}{sep}{key}" if parent_key else key
if isinstance(value, dict):
flattened.update(flatten_and_reverse(value, new_key, sep))
else:
flattened[new_key] = value
# 平坦化した辞書を反転
return {v: k for k, v in flattened.items()}
result = flatten_and_reverse(nested_config)
print(result) # {'localhost': 'database_host', 5432: 'database_port', 'redis-server': 'cache_host', 6379: 'cache_port'}
高速化テクニック
大量データでのパフォーマンス比較
import timeit
# 大量データの準備
large_dict = {f'key_{i}': i for i in range(100000)}
# 方法1: 辞書内包表記
def method1(dictionary):
return {v: k for k, v in dictionary.items()}
# 方法2: for文
def method2(dictionary):
result = {}
for k, v in dictionary.items():
result[v] = k
return result
# 方法3: dict()コンストラクタ
def method3(dictionary):
return dict((v, k) for k, v in dictionary.items())
# パフォーマンステスト(小規模データで実行)
small_dict = {f'key_{i}': i for i in range(1000)}
time1 = timeit.timeit(lambda: method1(small_dict), number=1000)
time2 = timeit.timeit(lambda: method2(small_dict), number=1000)
time3 = timeit.timeit(lambda: method3(small_dict), number=1000)
print(f"辞書内包表記: {time1:.4f}秒")
print(f"for文: {time2:.4f}秒")
print(f"dict()コンストラクタ: {time3:.4f}秒")
メモリ効率的な処理
def memory_efficient_reverse(large_dict, chunk_size=10000):
"""メモリ効率的な辞書反転"""
reversed_dict = {}
items = list(large_dict.items())
# チャンク単位で処理
for i in range(0, len(items), chunk_size):
chunk = items[i:i + chunk_size]
for key, value in chunk:
reversed_dict[value] = key
return reversed_dict
# 使用例
large_data = {f'item_{i}': i for i in range(50000)}
result = memory_efficient_reverse(large_data)
print(f"処理完了: {len(result)}件")
エラーハンドリング
安全な反転処理
def safe_reverse_dict(dictionary, handle_duplicates='ignore'):
"""安全な辞書反転(エラーハンドリング付き)"""
if not isinstance(dictionary, dict):
raise TypeError("引数は辞書である必要があります")
reversed_dict = {}
duplicates = []
for key, value in dictionary.items():
# ハッシュ可能かチェック
try:
hash(value)
except TypeError:
print(f"警告: 値 '{value}' はハッシュ不可能のためスキップ")
continue
if value in reversed_dict:
duplicates.append((key, value))
if handle_duplicates == 'error':
raise ValueError(f"重複する値: {value}")
elif handle_duplicates == 'list':
if not isinstance(reversed_dict[value], list):
reversed_dict[value] = [reversed_dict[value]]
reversed_dict[value].append(key)
# 'ignore'の場合は上書き
else:
reversed_dict[value] = key
return reversed_dict, duplicates
# 使用例
test_data = {'a': 1, 'b': 2, 'c': 1, 'd': [1, 2, 3]} # リストはハッシュ不可能
result, dups = safe_reverse_dict(test_data, handle_duplicates='list')
print("反転結果:", result)
print("重複:", dups)
型チェック付き反転
from typing import Dict, Any, Union, List
def typed_reverse_dict(
dictionary: Dict[Any, Any],
value_types: tuple = None
) -> Dict[Any, Union[Any, List[Any]]]:
"""型チェック付き辞書反転"""
if value_types is None:
value_types = (str, int, float, bool, tuple)
reversed_dict = {}
skipped = []
for key, value in dictionary.items():
# 指定された型かチェック
if not isinstance(value, value_types):
skipped.append((key, value, type(value).__name__))
continue
# ハッシュ可能かチェック
try:
hash(value)
reversed_dict[value] = key
except TypeError:
skipped.append((key, value, "unhashable"))
if skipped:
print(f"スキップされた項目 ({len(skipped)}件):")
for key, value, reason in skipped:
print(f" {key}: {value} ({reason})")
return reversed_dict
# 使用例
mixed_data = {
'name': '太郎',
'age': 25,
'scores': [85, 92, 78], # リスト(スキップ)
'active': True,
'config': {'debug': True} # 辞書(スキップ)
}
result = typed_reverse_dict(mixed_data, (str, int, bool))
print("結果:", result)
実用的なユーティリティ関数
双方向辞書クラス
class BiDict:
"""双方向辞書クラス"""
def __init__(self, initial_dict=None):
self.forward = initial_dict.copy() if initial_dict else {}
self.reverse = {v: k for k, v in self.forward.items()}
def set(self, key, value):
"""キー・値のペアを設定"""
# 既存の逆方向マッピングを削除
if key in self.forward:
old_value = self.forward[key]
del self.reverse[old_value]
if value in self.reverse:
old_key = self.reverse[value]
del self.forward[old_key]
self.forward[key] = value
self.reverse[value] = key
def get_by_key(self, key):
"""キーから値を取得"""
return self.forward.get(key)
def get_by_value(self, value):
"""値からキーを取得"""
return self.reverse.get(value)
def remove_by_key(self, key):
"""キーでペアを削除"""
if key in self.forward:
value = self.forward[key]
del self.forward[key]
del self.reverse[value]
def __str__(self):
return f"BiDict({self.forward})"
# 使用例
bd = BiDict({'apple': 'りんご', 'banana': 'バナナ'})
print(bd.get_by_key('apple')) # 'りんご'
print(bd.get_by_value('バナナ')) # 'banana'
bd.set('orange', 'オレンジ')
print(bd) # BiDict({'apple': 'りんご', 'banana': 'バナナ', 'orange': 'オレンジ'})
条件付き反転関数
def conditional_reverse(dictionary, condition=None, transform=None):
"""条件付き辞書反転"""
if condition is None:
condition = lambda k, v: True
if transform is None:
transform = lambda k, v: (v, k)
result = {}
for key, value in dictionary.items():
if condition(key, value):
new_key, new_value = transform(key, value)
try:
hash(new_key) # ハッシュ可能かチェック
result[new_key] = new_value
except TypeError:
print(f"警告: {new_key} はハッシュ不可能のためスキップ")
return result
# 使用例
data = {'name': '太郎', 'age': 25, 'score': 85, 'active': True}
# 数値のみ反転
numeric_only = conditional_reverse(
data,
condition=lambda k, v: isinstance(v, (int, float)),
transform=lambda k, v: (v, k.upper())
)
print(numeric_only) # {25: 'AGE', 85: 'SCORE'}
まとめ
Python辞書のキーと値の入れ替えは、データ処理において非常に重要な技術です。適切な方法を選択することで、効率的で安全な処理が可能になります。
基本的な反転手法
- 辞書内包表記が最もシンプルで推奨される方法
- for文はより複雑な処理が必要な場合に使用
重複値への対応
- 単純な上書きか、リスト化かを用途に応じて選択
- 最初の値のみ保持する方法も有効
実用的なポイント
- エラーハンドリングを必ず実装
- 大量データではパフォーマンスを考慮
- 型チェックでバグを防止
高度なテクニック
- 双方向辞書クラスで相互変換を効率化
- 条件付き反転で柔軟な処理を実現
- メモリ効率を考慮した処理方法
これらの技術を適切に組み合わせることで、様々なデータ変換や検索の高速化を実現できるでしょう。
■プロンプトだけでオリジナルアプリを開発・公開してみた!!
■AI時代の第一歩!「AI駆動開発コース」はじめました!
テックジム東京本校で先行開始。
■テックジム東京本校
「武田塾」のプログラミング版といえば「テックジム」。
講義動画なし、教科書なし。「進捗管理とコーチング」で効率学習。
より早く、より安く、しかも対面型のプログラミングスクールです。
<短期講習>5日で5万円の「Pythonミニキャンプ」開催中。
<月1開催>放送作家による映像ディレクター養成講座
<オンライン無料>ゼロから始めるPython爆速講座

