functools

【Python】reduce関数の使い方の基本 ~リスト要素の畳み込み~

【Python】reduce関数の使い方の基本 ~リスト要素の畳み込み~

Pythonでreduce関数を使ってリストの要素を畳み込む方法を解説します。

reduce関数でリスト要素を畳み込む

reduce関数は、関数と処理対象のイテラブルを受け取り、そのイテラブルの要素を指定した関数を使って畳み込むための関数です。

このように引数に関数を受け取る関数は高階関数と言います。for文で処理しても同じ処理ができますが、繰り返し処理を書かずともシンプルに記載できる点がメリットです。

reduce関数は、Python2ではmap関数やfilter関数同様にPythonの組み込み関数でした。しかし、Python3からはfunctoolsモジュールに移動したため、この関数を使用する際にはfunctoolsのインポートが必要となりました。

reduce関数は関数型プログラミング言語でも中心的な関数です。なお、一部の言語ではfoldという関数名で呼ばれることもあります。Pythonはマルチパラダイムの言語と言われているため、厳密ではありませんが関数型のプログラミングスタイルもサポートしており、reduce関数が利用できるようになっています。

本記事では、リストを使った例を用いて、reduce関数の使い方の基本を紹介します。

Note

reduce関数と同じく関数型プログラミングに関連のある関数としてmap関数、filter関数、partial関数があります。以下のページでまとめていますので興味があれば参考にしてください。

reduce関数の基本的な使い方

reduce関数の基本的な構文は以下のようになります。

reduce関数
from functools import reduce

result = reduce(関数, イテラブル)

reduce関数はfunctoolsモジュール内にあるため、上記のようにインポートしてください。

reduce関数は、イテラブルの要素を一つずつ取得し、それらの要素に累積的に指定した関数を適用して結果を畳み込んでいきます。例えば、関数funcとリスト[a, b, c, d]というものがあった時に、reduce(func, [a, b, c, d])は、func(func(func(a, b), c), d)と同じです。

よくreduce関数と一緒に紹介されるmap関数やfilter関数は返却値としてイテレータを返すので、無限に続くようなシーケンスでも動作させることができます(もちろんlist等に変換しようとしたり、for文でループに使うようなことをすると終了しなくなります)。

一方で、reduce関数は計算のためにイテラブル内の全ての要素を評価しないといけないため、無限のシーケンスでは利用することはできません。

基本的な使い方

以下の例で、reduce関数の基本的な使い方を確認します。

from functools import reduce


def add_nums(x, y):
    """値を足し算する"""
    return x + y


def multiply_nums(x, y):
    """値を掛け算する"""
    return x * y


if __name__ == "__main__":
    tmp_list = [1, 2, 3, 4, 5]

    # reduce関数でadd_nums関数を適用する
    result = reduce(add_nums, tmp_list)
    print(result)

    # reduce関数でmultiply_nums関数を適用する
    result = reduce(multiply_nums, tmp_list)
    print(result)
【実行結果】
15
120

上記の例では、受け取った値を足し算するadd_nums関数と掛け算をするmultiply_nums関数を用意し、tmp_listの各要素に順に関数を適用しています。

reduce関数を呼び出している部分では「reduce(add_nums, tmp_list)」というように関数と処理対象のリストを渡しています。ここでポイントは、関数を渡す際に()がないことです。関数はadd_nums(1, 2)のように()で引数を指定すると関数を実行することを意味しますが、()がない場合は関数そのものを表します。reduce関数は、受け取ったadd_numsmultiply_numsといった関数を内部で実行しているわけです。

reduce関数でadd_numstmp_listを実行した場合、計算内容としては「((((1+2)+3)+4)+5) = 15」です。同様にmultiply_numsの場合は、「((((1*2)*3)*4)*5) = 120」となります。

このようにreduce関数を用いることで、リストの要素に順に関数を適用して畳み込むような演算をすることができます。

ラムダ関数(無名関数)を使用する場合

reduce関数は、ラムダ関数(無名関数)と組み合わせることで、一時的な小さな関数を定義せずに使用することができます。

ラムダ関数は関数型プログラミングでもとても重要な概念です。ラムダ関数については「ラムダ(lambda)関数:無名関数の使い方」でまとめていますので興味があれば参考にしてください。

上記で見てきたadd_nums関数やmultiply_nums関数をラムダ関数にして使う例を以下で見てみましょう。

from functools import reduce

tmp_list = [1, 2, 3, 4, 5]

# reduce関数でラムダ関数を使って足し算を適用する
result = reduce(lambda x, y: x + y, tmp_list)
print(result)

# reduce関数でラムダ関数を使って掛け算を適用する
result = reduce(lambda x, y: x * y, tmp_list)
print(result)
【実行結果】
15
120

これまでの例でadd_nums関数を指定した部分で「lambda x, y: x + y」というラムダ関数で置き換えて指定しています。また、同様にmultiply_numsの代わりに「lambda x, y: x * y」としています。結果はadd_nums関数やmultiply_nums関数を指定した時と一緒になっていることが分かります。

ラムダ関数は無名関数ともいわれる通り、関数名はありませんが式そのものが関数扱いになります。そのため、reduce関数にラムダ関数を渡すことでリスト要素に対して累積的に関数を適用して畳み込みをすることができます。

まとめ

Pythonでreduce関数を使ってリストの要素を畳み込む方法を解説しました。

reduce関数は、関数と処理対象のイテラブルを受け取り、そのイテラブルの要素を指定した関数を使って畳み込むための関数です。reduce関数は関数型プログラミング言語でも中心的な関数ですがPythonでも使用できます。

reduce関数は、Python2ではmap関数やfilter関数同様にPythonの組み込み関数でした。しかし、Python3からはfunctoolsモジュールに移動したため、この関数を使用する際にはfunctoolsのインポートが必要になっています。

reduce関数はfor文を用いなくてもシンプルに関数の畳み込みができることが特徴です。非常に強力な機能ですが、reduce関数の適用が常に最適な選択というわけではありません。場合によってはfor文で書いた方が可読性が上がる可能性もあります。

目的に応じて適切に方法を選択できるようにreduce関数の使い方を理解し、覚えておいてもらうとよいかと思います。