Pythonicなコードへ!map, filter, zipなどループ処理で役立つ組み込み関数5選

Python

Pythonを学び始めると、forループは真っ先に覚える強力なツールの一つです。しかし、リストの全要素に同じ処理をしたり、特定の条件で絞り込んだりするたびにforループを書いていると、コードが冗長になってしまうことも。

実は、Pythonにはそうした繰り返し処理をより簡潔に、そしてスマートに書くための便利な組み込み関数が多数用意されています。

この記事では、forループを置き換えることで、あなたのコードをより「Pythonic(Pythonらしい)」にしてくれる5つの代表的な関数 (map, filter, zip, enumerate, reversed) を、具体的なサンプルコードと共に解説します。

はじめに:そのforループ、もっと「Pythonらしく」書けるかも?

この記事でわかること

  • map(): 全要素に同じ処理を一括適用する方法
  • filter(): 条件に合う要素だけを賢く抽出する方法
  • zip(): 複数のリストをまとめて同時に扱う方法
  • enumerate(): インデックス番号付きでループする方法
  • reversed(): リストなどを逆順にする方法

これらの関数には一つ重要な共通点があります。それは、多くが結果としてリストそのものではなく、「イテレータ」というものを返す点です。イテレータは「要素を一つずつ取り出すための設計図」のようなもので、メモリ効率が良いという特徴があります。

中身を確認したいときは list() 関数でリストに変換する必要がある、という点だけ頭の片隅に置いて読み進めてください。

map()関数:全要素に同じ処理を一括適用

map()は、リストなどの各要素に対して、指定した関数を適用し、その結果をまとめて返す関数です。

基本的な使い方 – map(関数, イテラブル)

例えば、数値のリストをすべて文字列に変換したい場合、forループだとこう書きます。

numbers = [1, 2, 3, 4, 5]
str_numbers_loop = []
for n in numbers:
    str_numbers_loop.append(str(n))
# str_numbers_loop は ['1', '2', '3', '4', '5']

map()を使うと、この処理がわずか1行で書けます。

numbers = [1, 2, 3, 4, 5]
# str関数をnumbersの全要素に適用する
str_numbers_map = map(str, numbers)

# 中身を確認するためにlist()でリスト化
print(list(str_numbers_map))
# 出力: ['1', '2', '3', '4', '5']

lambda式と組み合わせてスマートに記述する

map()は、その場限りの簡単な処理を定義できるlambda式と組み合わせるとさらに強力です。例えば、全要素を2倍する処理は次のようになります。

numbers = [1, 2, 3, 4, 5]
doubled_numbers = map(lambda x: x * 2, numbers)
print(list(doubled_numbers))
# 出力: [2, 4, 6, 8, 10]

filter()関数:条件に合う要素だけを賢く抽出

filter()は、リストなどの各要素を特定の関数で判定し、結果がTrueになる要素だけを抽出する関数です。

基本的な使い方 – filter(関数, イテラブル)

例えば、数値のリストから偶数だけを取り出したい場合を考えます。

numbers = [1, 2, 3, 4, 5, 6, 7, 8]

# 偶数かどうかを判定する関数を定義
def is_even(n):
    return n % 2 == 0

even_numbers = filter(is_even, numbers)
print(list(even_numbers))
# 出力: [2, 4, 6, 8]

lambda式を使った実践的なフィルタリング例

この処理もlambda式を使えば、関数を別途定義する必要がなくなり、より簡潔になります。

numbers = [1, 2, 3, 4, 5, 6, 7, 8]
even_numbers = filter(lambda x: x % 2 == 0, numbers)
print(list(even_numbers))
# 出力: [2, 4, 6, 8]

map()filter()を使うことで、「何をするか(What)」が明確になり、forループで「どのようにやるか(How)」を記述するよりもコードの意図が伝わりやすくなります。

zip()関数:複数のリストをまとめて同時に処理

zip()は、複数のリストやタプルを受け取り、同じインデックスにある要素同士をペアにしたタプルを生成します。複数の関連するデータを同時に処理したい場合に非常に便利です。

基本的な使い方 – zip(イテラブル1, イテラブル2, ...)

names = ['佐藤', '鈴木', '高橋']
ages = [25, 32, 28]

# 2つのリストをまとめる
profile_zip = zip(names, ages)
print(list(profile_zip))
# 出力: [('佐藤', 25), ('鈴木', 32), ('高橋', 28)]

forループと組み合わせることで、それぞれのリストから対応する要素をスマートに取り出せます。

for name, age in zip(names, ages):
    print(f'{name}さんの年齢は{age}歳です。')

要素数が異なるリストをzipするとどうなる?

zip()は、引数として渡されたリストの中で最も要素数が少ないリストに合わせて処理を行います。余った要素は無視されます。

names = ['佐藤', '鈴木', '高橋']
scores = [88, 92] # 要素数が少ない

# 要素数が少ないscoresに合わせられる
result = zip(names, scores)
print(list(result))
# 出力: [('佐藤', 88), ('鈴木', 92)]
# '高橋'はペアになる相手がいないため無視される

enumerate()関数:インデックス番号付きでループ処理

enumerate()は、forループ内でリストのインデックス番号と要素を同時に取り出したいときに使います。

基本的な使い方 – enumerate(イテラブル)

ランキングの表示のように、「何番目の要素か」が欲しい場合に最適です。

fruits = ['りんご', 'バナナ', 'みかん']
for index, fruit in enumerate(fruits):
    print(f'{index + 1}位: {fruit}')

# 出力:
# 1位: りんご
# 2位: バナナ
# 3位: みかん

なぜカウンター変数が不要になるのか

enumerateを使わない場合、ループの外でカウンター変数を初期化し、ループ内でインクリメントする手間が必要です。

# enumerateを使わない場合
count = 0
for fruit in fruits:
    print(f'{count + 1}位: {fruit}')
    count += 1

enumerate()を使うことで、このようなカウンター変数が不要になり、コードがスッキリとします。

reversed()関数:リストやタプルを逆順に

reversed()は、リストや文字列などのシーケンスを逆順にしたイテレータを返します。

基本的な使い方 – reversed(シーケンス)

numbers = [1, 2, 3, 4, 5]
reversed_numbers = reversed(numbers)

print(list(reversed_numbers))
# 出力: [5, 4, 3, 2, 1]

元のリストnumbers自体は変更されないのがポイントです。

スライス ([::-1]) との違いは?

Pythonではスライス表記 [::-1] でも逆順のリストを作成できます。

numbers = [1, 2, 3, 4, 5]
reversed_list_slice = numbers[::-1]
print(reversed_list_slice) # 出力: [5, 4, 3, 2, 1]

主な違いは、reversed()がメモリ効率の良いイテレータを返すのに対し、スライスは新しい逆順のリストをメモリ上に作成する点です。巨大なリストを扱う場合はreversed()の方が効率的です。

まとめ:便利な組み込み関数でPythonicなコードを書こう

今回は、forループをより簡潔でスマートにする5つの組み込み関数を紹介しました。

  • map(): 全要素に関数を適用
  • filter(): 条件に合う要素で絞り込み
  • zip(): 複数のリストを束ねる
  • enumerate(): インデックスと要素を同時に取得
  • reversed(): シーケンスを逆順にする

これらの関数を使いこなすことは、Pythonらしい、効率的で読みやすいコードを書くための大きな一歩です。日々のコーディングでぜひ活用してみてください。

コメント

タイトルとURLをコピーしました