Pythonのmap()でリストの要素に関数・処理を適用
Pythonのmap()
を使うと、イテラブル(リストやタプルなど)のすべての要素に組み込み関数やlambda
(ラムダ式、無名関数)、def
で定義した関数などを適用できる。
なお、後半で述べるように、map()
の処理はリスト内包表記やジェネレータ式で代用可能であり、多くの場合、リスト内包表記・ジェネレータ式を使用するほうが好ましいとされている。
- 関連記事: Pythonリスト内包表記の使い方
map()の基本的な使い方
map()
の第一引数に適用する関数(呼び出し可能オブジェクト)、第二引数にリストなどのイテラブルオブジェクトを指定する。
Python3のmap()はイテレータを返す
絶対値を返す組み込み関数abs()
を適用する例を示す。
Python3のmap()
はmap
型のオブジェクト(イテレータ)を返し、そのままprint()
しても中身の値は出力されない。
l = [-2, -1, 0]
print(map(abs, l))
# <map object at 0x10651a400>
print(type(map(abs, l)))
# <class 'map'>
イテレータの値はfor
文などで取り出せる。
for i in map(abs, l):
print(i)
# 2
# 1
# 0
for
文を使う場合は、map()
を使わずにブロック内で処理を実行しても同じ結果となる。
for i in l:
print(abs(i))
# 2
# 1
# 0
なお、Python2のmap()
はリストを返す。Python2のコードをPython3で実行する場合は注意。
リストに変換
結果をリストに変換したい場合はlist()
を使う。
l = [-2, -1, 0]
print(list(map(abs, l)))
# [2, 1, 0]
以降のサンプルコードでは、便宜上、リストに変換した結果を出力する。
文字列のリストにlen()
を適用して文字数のリストに変換する例。
- 関連記事: Pythonで文字列の長さ(文字数)を取得
l_s = ['apple', 'orange', 'strawberry']
print(list(map(len, l_s)))
# [5, 6, 10]
map()
の第二引数にはイテラブルオブジェクトを指定できる。リストだけでなくタプルやrange
なども指定可能。
- 関連記事: Pythonのrange関数の使い方
print(list(map(abs, range(-2, 1))))
# [2, 1, 0]
lambda(ラムダ式、無名関数)を適用
組み込み関数ではない任意の処理を適用したい場合、lambda
(ラムダ式、無名関数)を用いる。
l = [-2, -1, 0]
print(list(map(lambda x: x**2, l)))
# [4, 1, 0]
defで定義した関数を適用
ラムダ式ではなくdef
で任意の関数を定義してmap()
の第一引数に指定することも可能。
l = [-2, -1, 0]
def square(x):
return x**2
print(list(map(square, l)))
# [4, 1, 0]
複数のイテラブル(リストなど)を引数に指定
map()
は第三引数以降にさらにイテラブルを指定できる。
複数のイテラブルを指定した場合、第一引数にはその数の引数を受け取る関数・ラムダ式を指定する必要がある。イテラブルの数と第一引数の関数・ラムダ式が受け取る引数の数が一致していないとエラー。
l_1 = [1, 2, 3]
l_2 = [10, 20, 30]
print(list(map(lambda x, y: x * y, l_1, l_2)))
# [10, 40, 90]
# print(list(map(abs, l_1, l_2)))
# TypeError: abs() takes exactly one argument (2 given)
イテラブルのサイズ(要素数)が異なる場合、多い分は無視される。
l_3 = [100, 200, 300, 400]
print(list(map(lambda x, y, z: x * y * z, l_1, l_2, l_3)))
# [1000, 8000, 27000]
リスト内包表記・ジェネレータ式で代用
map()
と同等の処理はリスト内包表記やジェネレータ式でも実現できる。
l = [-2, -1, 0]
print([abs(x) for x in l])
# [2, 1, 0]
print([x**2 for x in l])
# [4, 1, 0]
l_1 = [1, 2, 3]
l_2 = [10, 20, 30]
print([x * y for x, y in zip(l_1, l_2)])
# [10, 40, 90]
list(map())
のようにリストを取得したい場合はリスト内包表記、map()
のようにイテレータを取得したい場合はジェネレータ式を使えばよい。
- 関連記事: Pythonリスト内包表記の使い方
以下のStack Overflowの質問にもあるように、ほとんどの場合、map()
よりもリスト内包表記・ジェネレータ式を使うほうがコードが簡潔・明解で好ましいとされている。
書籍『Effective Python』でもmap()
よりもリスト内包表記を使うべきと書かれている。
処理速度に関しては、以下の回答が示されている。
- python - List comprehension vs map - 40948713 - Stack Overflow
- リスト内包表記と
list(map())
- 組み込み関数を適用する場合、
list(map())
のほうが速い - ラムダ式を適用する場合、リスト内包表記のほうが速い
- 組み込み関数を適用する場合、
- ジェネレータ式と
map()
map()
のほうが速い
- リスト内包表記と
ただし、処理速度は様々な要因で変動する可能性もあるので、処理速度が重要な状況であればなるべく想定に近い環境および処理で実際に計測してみることをおすすめする。
NumPyで代用(数値計算の場合)
数値のリストの場合、map()
と同等の処理はNumPyでも実現できる。map()
やリスト内包表記よりもさらに明解なコードになる。
import numpy as np
a = np.array([-2, -1, 0])
print(np.abs(a))
# [2 1 0]
print(a**2)
# [4 1 0]
a_1 = np.array([1, 2, 3])
a_2 = np.array([10, 20, 30])
print(a_1 * a_2)
# [10 40 90]
大規模なリストに対する処理や複雑な処理はNumPyのほうが高速。NumPyには様々な関数も提供されているので、数値の配列を対象とする処理を行う場合は試してみるとよい。
- 関連記事: NumPy関連記事まとめ