map()関数

map()関数

map()

 map() はリストやタプルのすべての要素に同じ演算を適用する関数です。map() は Python の組み込み高階関数なので、モジュールをインポートせずにいつでも使えます。

 書式の説明から入ると分かりにくいので、最初は具体例を使って説明します。まず、受け取った引数を 2 倍にして返す関数を用意しておきます。

# PYTHON_MAP

# In[1]

# 数値を2倍する関数を定義
def double(x):
    return 2 * x

 たとえば、引数 x に 10 を渡せば 20 が返ります:

# In[2]

# 10を2倍する
double(10)
20

 次に、1 ~ 9 の数値を格納したリストを定義します。

# In[3]

# 1~9の数値をリストに格納する
# numbers=[1, 2, 3, 4, 5, 6, 7, 8, 9]
numbers = range(1, 10)

 この numbers の要素すべてを 2 倍にしたいと考えて、double() 関数に放り込んでも、エラーが返ります。

# In[4]

double(numbers)
TypeError: unsupported operand type(s) for *: 'int' and 'range'

 double() が受け取る引数 x は 1 つの数値のみです。Python の算術演算子は、シーケンスの複数要素に演算をほどこすことはできません。

 そこで登場するのが map() 関数です。
 map() の第 1 引数と第 2 引数に、それぞれ double, numbers を渡してみましょう。戻り値は double_numbers という変数に格納しておくことにします。

# In[5]

# map()にdoubleとnumbersを渡す
double_numbers = map(double, numbers)

 double_numbers には numbers の各要素が 2 倍されたリスト [2, 4, 6, 8, 10, 12, 14, 16, 18] が入っていることを期待しますが、double_numbers の中身を表示させようとしても上手くいきません。

# In[6]

double_numbers
<map at 0x7ff7af782898>

 実行結果は、map() 関数の戻り値が map オブジェクト であることを示しています。map オブジェクトは イテレータ の一種です。イテレータとは中身を順番に1個ずつ取り出す機能をもつオブジェクトのことです。Python では、next() 関数を使ってイテレータから要素を取り出せます。試しに、先頭から 3 個の要素を抜き出してみましょう。

# In[7]

# 先頭から3個の要素を抜き出す
for i in range(3):
    data = next(double_numbers)
    print(data)
2
4
6

 取り出した要素はイテレータから消えてしまいます。
 もう一度 next() 関数を使うと、8 が取り出されます:

# In[8]

# double_numbersから次の要素を取り出す
next(double_numbers)
8

 イテレータは用途によっては便利なオブジェクトですが、リストのようなシーケンスが欲しい場合もあるでしょう。list() を使えば、イテレータの要素をリストに展開できます。

# In[9]

# mapオブジェクトをリストに変換
double_numbers = list(map(double, numbers))

# double_numbersの中身を表示
double_numbers
[2, 4, 6, 8, 10, 12, 14, 16, 18]

 map() 関数の書式を載せておきます。

map(関数, イテラブル)

 第 2 引数のイテラブルとは、イテレータに変換できるオブジェクトを指します。第 2 引数に渡したオブジェクトがイテラブルでなければエラーが返ります。たとえば、map() の第 2 引数に int (整数型オブジェクト) を渡してみると、TypeError が返ります。

# In[10]

# map()の第2引数にintを渡してみる
double_numbers = list(map(double, 10))
TypeError: 'int' object is not iterable

 第 1 引数に lambda式 関数を渡すこともできます。

# In[11]

# numbersの各要素を2倍にする
double_numbers = map(lambda x: 2*x, numbers)

# mapオブジェクトをリストに展開
double_numbers = list(double_numbers)

double_numbers
[2, 4, 6, 8, 10, 12, 14, 16, 18]

 数値や文字列の後ろに "円" を添える関数を用意して、商品の価格リストの各要素に "円" を付け加えるようなこともできます。

# In[12]

# 後ろに"円"を添える関数
def add_yen(x):
    return str(x) + "円"

# 商品の価格リスト
my_price = [740, 1200, 950, 580, 1630]

# 価格リストの全ての要素に"円"を付け加える
list(map(add_yen, my_price))
['740円', '1200円', '950円', '580円', '1630円']

 map() を使うと、for 構文を一切使わずに、簡潔なコードで複雑なループ処理を実行できます。たとえば、map() の第 1 引数に、複引数関数を渡して、リストの要素同士の演算ができます。

 一例として、2 つのリストの要素同士を加える操作を行なってみましょう。最初に 2 つの引数を加える関数を定義して、数値が格納されたリストを 2 種類用意しておきます。

# In[13]

# 受け取った引数を加える関数を定義
def add(x, y):
    return x + y

# 同じ要素数をもつ2種類のリストを用意
list_A = [1, 2, 3]
list_B = [10, 20, 30]

 map() の第 1 引数に add を、第 2 引数と第 3 引数に list_A と list_B を渡して mapオブジェクトを生成し、リストに変換してみます。

# In[14]

# list_Aとlist_Bの要素同士を加えたmapオブジェクトを生成
my_map = map(add, list_A, list_B)

# mapオブジェクトの全要素をリストに展開
list(my_map)
[11, 22, 33]

 2 種類のリストの要素同士を加算した新しいリストが作成されました。第 2 引数と第 3 引数に渡すイテラブルの要素数は異なっていても構いません。その場合、少ない要素数をもつほうのリストに合わせて map オブジェクトが生成され、余った要素は捨てられます。

# In[15]

# 2種類のリストを用意
list_A = [5, 10, 15, 20, 25]
list_B = [100, 200]

# list_Aとlist_Bの要素同士を加えたmapオブジェクトを生成
my_map = map(add, list_A, list_B)

# mapオブジェクトの全要素をリストに展開
list(my_map)
[105, 210]

 map() には任意の個数の引数を受け取る関数を渡せますし、引数の個数と同じ数のイテラブルを渡すことになります。したがって、より一般的な map() 関数の書式は以下のようになります。

map(関数, *イテラブル)

 「*」 は任意の数の引数を渡せることを意味する記号です。