問題の背景
関数 map() は関数型プログラミング(Lispから)に由来し、目的はシーケンスの各要素に関数を適用し、結果の新しいイテラブルオブジェクトを返すことです。Python では、マップはリスト内包表記やジェネレータ式が登場するずっと前から存在しており、特に大規模なデータ処理パイプラインで広く使用されています。
問題点
コレクションの各要素を何らかのルールに従って変更する必要がある場合、forループのような解決策はすぐに煩雑で読みづらくなります。リスト内包表記や map() を使うことで、意図をコンパクトに表現できます。このアプローチの違いを理解して、適切なツールを選択することが重要です。
解決策
map(func, iterable) は、元のシーケンスの要素を関数 func で変換した怠惰なイテレータを生成しますdef square(x): return x * x squares = map(square, [1, 2, 3]) print(list(squares)) # [1, 4, 9]
リスト内包表記 [square(x) for x in [1, 2, 3]] は同様のことを行いますが、すぐにリストを返し、ジェネレータ式 (square(x) for x in [1, 2, 3]) は怠惰なジェネレータです。
主な特徴:
Python 3でmap()はリストを返しますか?
いいえ、Python 3以降、map()はリストではなく怠惰なイテレータを返します。リストを得るには、結果を手動でlist()でラップする必要があります。
res = map(str.upper, ['a', 'b']) print(res) # <map object ...> print(list(res)) # ['A', 'B']
map()を使ってフィルタリング条件を関数内に追加できますか?
いいえ、map() は要素をフィルタリングせず、変換のみを行います。フィルタリングにはfilter()やリスト内包表記を使用してください。
result = map(str.upper, ['a', 'b', None]) # Noneが入ると、mapはエラーを引き起こします。 # filterを使ってNoneをmapの前に取り除くことができます。
map()を使って二つのシーケンスを同時に反復処理することはできますか?
はい、map()は任意の数のシーケンスを受け入れることができ、変換関数は同じ数の引数を受け取る必要があります。
x = [1, 2, 3] y = [10, 20, 30] result = map(lambda a, b: a + b, x, y) print(list(result)) # [11, 22, 33]
開発者はすぐにリストを得ると期待しています。
mapped = map(abs, [-1, -2, -3]) print(mapped[1]) # TypeError: 'map' object is not subscriptable
利点:
欠点:
フィルタリングにジェネレータ式を使用し、変換にmap()を使用する。
nums = range(-5, 6) positives = (x for x in nums if x > 0) sq = map(lambda n: n * n, positives) print(list(sq)) # [1, 4, 9, 16, 25, 36]
利点:
欠点: