Python変数・リスト値の交換完全ガイド – スワップ・入れ替えテクニックを徹底解説
Pythonでプログラミングをしていると、変数同士の値を交換したり、リスト内の要素を入れ替えたりする場面が頻繁にあります。ソートアルゴリズム、データの並べ替え、ゲームロジックなど、様々な用途で必要になる基本的かつ重要な操作です。この記事では、Pythonにおける値の交換・入れ替えの様々な手法を、基本的なテクニックから高度な応用例まで詳しく解説します。
目次
1. 基本的な変数の値交換
Pythonの優雅な交換記法
# 最もPythonicな方法(タプルのアンパッキング)
a = 10
b = 20
print(f"交換前: a={a}, b={b}")
a, b = b, a
print(f"交換後: a={a}, b={b}") # a=20, b=10
従来の一時変数を使った方法
# 他言語でよく使われる方法
x = 100
y = 200
# 一時変数を使用
temp = x
x = y
y = temp
print(f"交換後: x={x}, y={y}") # x=200, y=100
複数変数の同時交換
# 3つ以上の変数も同時に交換可能
a, b, c = 1, 2, 3
print(f"交換前: a={a}, b={b}, c={c}")
a, b, c = c, a, b # 循環シフト
print(f"交換後: a={a}, b={b}, c={c}") # a=3, b=1, c=2
2. リスト要素の交換
インデックスによる要素交換
# リスト内の特定位置の要素を交換
numbers = [1, 2, 3, 4, 5]
print(f"交換前: {numbers}")
# インデックス0と4の要素を交換
numbers[0], numbers[4] = numbers[4], numbers[0]
print(f"交換後: {numbers}") # [5, 2, 3, 4, 1]
関数による要素交換
def swap_elements(lst, i, j):
"""リストの指定位置の要素を交換"""
if 0 <= i < len(lst) and 0 <= j < len(lst):
lst[i], lst[j] = lst[j], lst[i]
return lst
data = ['a', 'b', 'c', 'd', 'e']
swap_elements(data, 1, 3)
print(data) # ['a', 'd', 'c', 'b', 'e']
3. ソートアルゴリズムでの交換
バブルソートでの要素交換
def bubble_sort(arr):
"""バブルソートの実装"""
n = len(arr)
for i in range(n):
for j in range(0, n - i - 1):
if arr[j] > arr[j + 1]:
# 隣接要素の交換
arr[j], arr[j + 1] = arr[j + 1], arr[j]
return arr
unsorted = [64, 34, 25, 12, 22, 11, 90]
sorted_arr = bubble_sort(unsorted.copy())
print(f"ソート結果: {sorted_arr}")
クイックソートでの分割処理
def quicksort_partition(arr, low, high):
"""クイックソートの分割処理"""
pivot = arr[high]
i = low - 1
for j in range(low, high):
if arr[j] <= pivot:
i += 1
# 要素の交換
arr[i], arr[j] = arr[j], arr[i]
arr[i + 1], arr[high] = arr[high], arr[i + 1]
return i + 1
def quicksort(arr, low, high):
"""クイックソートの実装"""
if low < high:
pi = quicksort_partition(arr, low, high)
quicksort(arr, low, pi - 1)
quicksort(arr, pi + 1, high)
data = [10, 7, 8, 9, 1, 5]
quicksort(data, 0, len(data) - 1)
print(f"クイックソート結果: {data}")
4. 2次元リストでの要素交換
行列の要素交換
# 2次元リスト(行列)での要素交換
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
print("交換前:")
for row in matrix:
print(row)
# (0,0) と (2,2) の要素を交換
matrix[0][0], matrix[2][2] = matrix[2][2], matrix[0][0]
print("\n交換後:")
for row in matrix:
print(row)
行と列の交換
def swap_rows(matrix, row1, row2):
"""行列の行を交換"""
if 0 <= row1 < len(matrix) and 0 <= row2 < len(matrix):
matrix[row1], matrix[row2] = matrix[row2], matrix[row1]
def swap_columns(matrix, col1, col2):
"""行列の列を交換"""
for row in matrix:
if 0 <= col1 < len(row) and 0 <= col2 < len(row):
row[col1], row[col2] = row[col2], row[col1]
# 使用例
data = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
print("元の行列:", data)
swap_rows(data, 0, 2) # 1行目と3行目を交換
print("行交換後:", data)
swap_columns(data, 0, 2) # 1列目と3列目を交換
print("列交換後:", data)
5. 辞書での値交換
辞書のキー・値の交換
# 辞書の値を交換
person1 = {"name": "Alice", "age": 25}
person2 = {"name": "Bob", "age": 30}
print(f"交換前: {person1}, {person2}")
# 年齢を交換
person1["age"], person2["age"] = person2["age"], person1["age"]
print(f"交換後: {person1}, {person2}")
辞書のキーと値を入れ替え
def swap_dict_keys_values(d):
"""辞書のキーと値を入れ替え"""
return {v: k for k, v in d.items()}
original = {"apple": "red", "banana": "yellow", "grape": "purple"}
swapped = swap_dict_keys_values(original)
print(f"元の辞書: {original}")
print(f"入れ替え後: {swapped}")
6. 文字列の文字交換
文字列内の文字を交換
def swap_string_chars(s, i, j):
"""文字列の指定位置の文字を交換"""
if not (0 <= i < len(s) and 0 <= j < len(s)):
return s
chars = list(s)
chars[i], chars[j] = chars[j], chars[i]
return ''.join(chars)
text = "Hello World"
result = swap_string_chars(text, 0, 6) # 'H' と 'W' を交換
print(f"元の文字列: {text}")
print(f"交換後: {result}") # "Wello Horld"
アナグラム生成での文字交換
import random
def generate_anagram(word):
"""単語の文字を交換してアナグラムを生成"""
chars = list(word)
# ランダムに複数回文字を交換
for _ in range(len(chars)):
i = random.randint(0, len(chars) - 1)
j = random.randint(0, len(chars) - 1)
chars[i], chars[j] = chars[j], chars[i]
return ''.join(chars)
original_word = "python"
anagram = generate_anagram(original_word)
print(f"元の単語: {original_word}")
print(f"アナグラム: {anagram}")
7. 高度な交換テクニック
条件付き交換
def conditional_swap(arr, condition_func):
"""条件に基づいて要素を交換"""
swapped = False
for i in range(len(arr) - 1):
if condition_func(arr[i], arr[i + 1]):
arr[i], arr[i + 1] = arr[i + 1], arr[i]
swapped = True
return swapped
# 偶数を前に、奇数を後ろに移動
numbers = [1, 4, 3, 6, 5, 8]
print(f"交換前: {numbers}")
# 右側が偶数で左側が奇数の場合に交換
while conditional_swap(numbers, lambda x, y: x % 2 == 1 and y % 2 == 0):
pass
print(f"交換後: {numbers}")
チェーン交換
def chain_swap(arr, indices):
"""複数の要素を連鎖的に交換"""
if len(indices) < 2:
return arr
# 一時的に最初の値を保存
temp = arr[indices[0]]
# 連鎖的に値を移動
for i in range(len(indices) - 1):
arr[indices[i]] = arr[indices[i + 1]]
# 最後の位置に最初の値を設定
arr[indices[-1]] = temp
return arr
data = ['A', 'B', 'C', 'D', 'E']
print(f"交換前: {data}")
# インデックス0→2→4→0の順で値を移動
chain_swap(data, [0, 2, 4])
print(f"交換後: {data}") # ['C', 'B', 'E', 'D', 'A']
8. オブジェクト指向での交換
クラスでの値交換
class Swappable:
def __init__(self, value):
self.value = value
def swap_with(self, other):
"""他のオブジェクトと値を交換"""
self.value, other.value = other.value, self.value
def __str__(self):
return str(self.value)
obj1 = Swappable(100)
obj2 = Swappable(200)
print(f"交換前: obj1={obj1}, obj2={obj2}")
obj1.swap_with(obj2)
print(f"交換後: obj1={obj1}, obj2={obj2}")
属性の交換
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def swap_attributes_with(self, other, *attributes):
"""指定した属性を他のオブジェクトと交換"""
for attr in attributes:
if hasattr(self, attr) and hasattr(other, attr):
self_val = getattr(self, attr)
other_val = getattr(other, attr)
setattr(self, attr, other_val)
setattr(other, attr, self_val)
def __str__(self):
return f"Person(name='{self.name}', age={self.age})"
alice = Person("Alice", 25)
bob = Person("Bob", 30)
print(f"交換前: {alice}, {bob}")
alice.swap_attributes_with(bob, 'age')
print(f"年齢交換後: {alice}, {bob}")
9. パフォーマンス最適化
高速な交換実装
import time
def benchmark_swap_methods(size=1000000):
"""各交換方法のパフォーマンス比較"""
# テストデータ
data1 = list(range(size))
data2 = list(range(size))
data3 = list(range(size))
# Pythonic交換
start = time.time()
for i in range(0, len(data1) - 1, 2):
data1[i], data1[i + 1] = data1[i + 1], data1[i]
pythonic_time = time.time() - start
# 一時変数を使った交換
start = time.time()
for i in range(0, len(data2) - 1, 2):
temp = data2[i]
data2[i] = data2[i + 1]
data2[i + 1] = temp
temp_var_time = time.time() - start
# インデックス交換関数
def fast_swap(lst, i, j):
lst[i], lst[j] = lst[j], lst[i]
start = time.time()
for i in range(0, len(data3) - 1, 2):
fast_swap(data3, i, i + 1)
function_time = time.time() - start
print(f"データサイズ: {size:,}")
print(f"Pythonic交換: {pythonic_time:.4f}秒")
print(f"一時変数交換: {temp_var_time:.4f}秒")
print(f"関数呼び出し: {function_time:.4f}秒")
benchmark_swap_methods(100000)
10. 実用的な応用例
ゲームでの位置交換
class GameBoard:
def __init__(self, size):
self.size = size
self.board = [[i * size + j for j in range(size)] for i in range(size)]
def swap_positions(self, pos1, pos2):
"""盤面上の2つの位置の値を交換"""
x1, y1 = pos1
x2, y2 = pos2
if (0 <= x1 < self.size and 0 <= y1 < self.size and
0 <= x2 < self.size and 0 <= y2 < self.size):
self.board[x1][y1], self.board[x2][y2] = \
self.board[x2][y2], self.board[x1][y1]
return True
return False
def display(self):
"""盤面を表示"""
for row in self.board:
print(' '.join(f'{cell:2d}' for cell in row))
# 使用例
game = GameBoard(3)
print("初期状態:")
game.display()
print("\n(0,0)と(2,2)を交換後:")
game.swap_positions((0, 0), (2, 2))
game.display()
データ分析での列交換
class DataTable:
def __init__(self, data, headers):
self.data = data
self.headers = headers
def swap_columns(self, col1, col2):
"""列を交換"""
if col1 in self.headers and col2 in self.headers:
idx1 = self.headers.index(col1)
idx2 = self.headers.index(col2)
# ヘッダーを交換
self.headers[idx1], self.headers[idx2] = \
self.headers[idx2], self.headers[idx1]
# データを交換
for row in self.data:
row[idx1], row[idx2] = row[idx2], row[idx1]
def display(self):
"""テーブルを表示"""
print(' | '.join(f'{h:>8}' for h in self.headers))
print('-' * (len(self.headers) * 11 - 1))
for row in self.data:
print(' | '.join(f'{cell:>8}' for cell in row))
# 使用例
data = [
['Alice', 25, 50000],
['Bob', 30, 60000],
['Charlie', 35, 70000]
]
headers = ['Name', 'Age', 'Salary']
table = DataTable(data, headers)
print("交換前:")
table.display()
print("\nAgeとSalary列を交換後:")
table.swap_columns('Age', 'Salary')
table.display()
11. エラーハンドリングと安全な交換
安全な交換関数
def safe_swap(container, i, j):
"""安全な要素交換関数"""
try:
# インデックスの有効性チェック
if not (0 <= i < len(container) and 0 <= j < len(container)):
raise IndexError(f"インデックスが範囲外: i={i}, j={j}, length={len(container)}")
# 型チェック
if not hasattr(container, '__setitem__'):
raise TypeError("交換できない型です")
# 交換実行
container[i], container[j] = container[j], container[i]
return True
except Exception as e:
print(f"交換エラー: {e}")
return False
# テスト
test_cases = [
([1, 2, 3, 4, 5], 0, 4), # 正常ケース
([1, 2, 3], 0, 5), # インデックス範囲外
("hello", 0, 1), # 不変オブジェクト
([], 0, 1) # 空リスト
]
for container, i, j in test_cases:
print(f"交換テスト {container}, {i}⇔{j}: ", end="")
result = safe_swap(list(container) if isinstance(container, str) else container, i, j)
if result:
print("成功")
else:
print("失敗")
12. 大規模データでの効率的な交換
バッチ交換処理
def batch_swap(data, swap_pairs):
"""複数の交換を一括処理"""
# 交換ペアの有効性チェック
valid_pairs = []
for i, j in swap_pairs:
if 0 <= i < len(data) and 0 <= j < len(data) and i != j:
valid_pairs.append((i, j))
# 交換実行
for i, j in valid_pairs:
data[i], data[j] = data[j], data[i]
return len(valid_pairs)
# 使用例
large_data = list(range(100))
swap_operations = [(0, 99), (1, 98), (2, 97), (3, 96), (4, 95)]
swapped_count = batch_swap(large_data, swap_operations)
print(f"{swapped_count}個の交換を実行")
print(f"最初の10要素: {large_data[:10]}")
print(f"最後の10要素: {large_data[-10:]}")
13. 数学的な交換パターン
巡回置換
def cyclic_swap(arr, cycle):
"""巡回置換を実行"""
if len(cycle) < 2:
return arr
# 巡回の最初の値を保存
temp = arr[cycle[0]]
# 巡回に沿って値を移動
for i in range(len(cycle) - 1):
arr[cycle[i]] = arr[cycle[i + 1]]
# 最後の位置に最初の値を設定
arr[cycle[-1]] = temp
return arr
# 使用例
data = ['A', 'B', 'C', 'D', 'E', 'F']
print(f"交換前: {data}")
# (0 → 2 → 4 → 0) の巡回置換
cyclic_swap(data, [0, 2, 4])
print(f"巡回置換後: {data}") # ['C', 'B', 'E', 'D', 'A', 'F']
フィッシャー・イェーツシャッフルでの交換
import random
def fisher_yates_shuffle(arr):
"""フィッシャー・イェーツシャッフル(交換ベース)"""
for i in range(len(arr) - 1, 0, -1):
j = random.randint(0, i)
arr[i], arr[j] = arr[j], arr[i]
return arr
# 使用例
deck = list(range(1, 14)) # トランプのカード(1-13)
print(f"シャッフル前: {deck}")
shuffled = fisher_yates_shuffle(deck.copy())
print(f"シャッフル後: {shuffled}")
まとめ
Pythonでの値の交換・入れ替えは、様々な手法とテクニックがあります:
基本的な交換手法
- タプルアンパッキング –
a, b = b, a(最もPythonic) - 一時変数使用 – 他言語との互換性を考慮した方法
- 関数化 – 再利用可能な交換ロジック
用途別の推奨手法
- シンプルな変数交換: タプルアンパッキング
- リスト要素交換: インデックス指定での直接交換
- 大量データ: バッチ処理による効率化
- エラーハンドリング重視: 安全な交換関数の使用
パフォーマンス特性
- 速度: タプルアンパッキング > 一時変数 > 関数呼び出し
- 可読性: タプルアンパッキング > 関数化 > 一時変数
- 安全性: 関数化 > タプルアンパッキング > 一時変数
適切な手法を選択することで、効率的で読みやすく、保守性の高いコードを実現できます。特にアルゴリズムの実装やデータ処理において、これらの交換テクニックは必須のスキルとなります。
■らくらくPython塾 – 読むだけでマスター
■プロンプトだけでオリジナルアプリを開発・公開してみた!!
■AI時代の第一歩!「AI駆動開発コース」はじめました!
テックジム東京本校で先行開始。
■テックジム東京本校
「武田塾」のプログラミング版といえば「テックジム」。
講義動画なし、教科書なし。「進捗管理とコーチング」で効率学習。
より早く、より安く、しかも対面型のプログラミングスクールです。
<短期講習>5日で5万円の「Pythonミニキャンプ」開催中。
<月1開催>放送作家による映像ディレクター養成講座
<オンライン無料>ゼロから始めるPython爆速講座


