map()関数とfilter()関数

map()関数とfilter()関数

map()関数

 map() はリストやタプルのすべての要素に同じ演算を適用する関数です。正確には [関数] と [イテラブルオブジェクト] を受け取って、[イテラブルオブジェクト] の各要素を関数に渡して各要素の戻り値を要素にもつイテレータを生成します。

 map(関数, イテラブル)

 map() は Python の組み込み高階関数なので、モジュールをインポートせずにいつでも使えます。

map()関数の基本的な使い方

 map() を使って、1 から 9 までの数の平方数 (2 乗した数) のリストを作成してみましょう。

# リストMAP01

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

# map()を使って平方数のイテレータを作成
square_numbers = map(square, range(1, 10))

# イテレータをリストに変換
print(list(square_numbers))
[1, 4, 9, 16, 25, 36, 49, 64, 81]

 map() の第 2 引数には Rangeオブジェクトを渡していますが、代わりに [1, 2, 3, 4, 5, 6, 7, 8, 9] というリストを渡しても同じ結果が得られます。map() の戻り値はイテレータなので、要素を一括して取得したい場合は、サンプルコードにあるようにリストに変換します。
 

lambda式とmap()関数

 lambda式(無名関数)を使えば関数を定義する手間が省けます。さきほどのサンプルコードを lambda式を使って書き換えると次のようになります。

# リストMAP02

# map()関数を使って平方数のイテレータを作成
square_numbers = map(lambda x : x**2, range(1, 10))

# イテレータをリストに変換
print(list(square_numbers))
[1, 4, 9, 16, 25, 36, 49, 64, 81]

 

map()でexp(n)のイテレータを作成

 自然数 1 ~ 3 を math.exp()関数に渡して e1, e2, e3 のリストを作成するコードを書いてみます。

# リストMAP03

# mathモジュールをインポート
import math

# map()を使ってexp(n)のイテレータを作成
square_numbers = map(math.exp, range(1, 4))

# イテレータをリストに変換
print(list(square_numbers))
[2.718281828459045, 7.38905609893065, 20.085536923187668]

 

map()による数値と文字列の結合

 数値と文字列が収められたリストの各要素を連結するときに、map()関数を使うと便利です。

# リストMAP04

# 数値と文字列を要素にもつリスト
my_date = [2018, "年", 11, "月", 9, "日"]

# map()を使ってすべての要素を文字列に変換
my_date = map(str, my_date)

# 要素を結合
my_date = ''.join(my_date)

print(my_date)
2018年11月9日

 このコードでは map() に str()関数とリストを渡して、リストの要素をすべて文字列に変換してから、join()メソッドで各要素をつなげています。
 

filter()関数

filter()関数の構文

 filter() は関数とイテラブルオブジェクトを受け取って、イテラブルの要素のうち関数が True を返す要素を抜き出してイテレータを構築します。

 filter(関数, イテラブル)

 たとえば、あるリストから 50 以上の数値だけを取り出してイテレータを生成するには次のようなコードを記述します。

# リストFLT01-1

# リストを作成
my_list = [12, 67, 45, 96, 58]

# リストの中から50以上の数字を抜き出してイテレータを生成
f = filter(lambda x : x > 50, my_list)

# イテレータから最初の数字を取得
print(next(f))
67

 同じようなことはリスト内包表記でも可能です。
 上のコードを内包表記で書き直すと次のようになります。

# リストFLT01-2

# リストを作成
my_list = [12, 67, 45, 96, 58]

# リストの中から50以上の数字を抜き出してイテレータを生成
new_list = [x for x in my_list if x > 50]

print(new_list)
[67, 96, 58]

 しかし、filter() はイテレータを、内包表記はリストを生成するという点が異なっています。大きなデータを扱う場合、イテレータのほうがメモリを節約できます。
 

filter()のサンプルコード

 filter() の応用例をいくつか載せておきます。

# リストFLT02-1

# 1~100の自然数の中から、12または19で割り切れる数を見つける

# 1~100までの数字のリストを作成
my_list = list(range(1, 101))

# 1~100のうち、12または19で割り切れる数を返すイテレータを作成
f = filter(lambda x : x % 12 == 0 or x % 19 == 0, my_list)

# イテレータからすべての要素を取り出す
print(list(f))
[12, 19, 24, 36, 38, 48, 57, 60, 72, 76, 84, 95, 96]

 

# リストFLT02-2
# リストから"S"を含む文字列を抽出

my_list = ["SML", "Haslkell", "Erlang", "Scheme", "Scala"]

# リストの中からSを含む要素を抜き出してイテレータを作成
f = filter(lambda x : x.find("S") != -1, my_list)

# イテレータからすべての要素を取り出す
print(list(f))
['SML', 'Scheme', 'Scala']

 str.find() は、指定した文字列の場所を返すメソッドですが、見つからない場合は -1 を返してきます。x.find("S") != -1 は「"S" が -1 でない」、すなわち「"S" が文字列のどこかに含まれる」を意味しています。