Python 3でフィルター、マップ、リデュースを使用する方法


321

filtermap、そしてreduce完全にPythonの2ここでの作業は一例です:

>>> def f(x):
        return x % 2 != 0 and x % 3 != 0
>>> filter(f, range(2, 25))
[5, 7, 11, 13, 17, 19, 23]

>>> def cube(x):
        return x*x*x
>>> map(cube, range(1, 11))
[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]

>>> def add(x,y):
        return x+y
>>> reduce(add, range(1, 11))
55

しかし、Python 3では、次の出力を受け取ります。

>>> filter(f, range(2, 25))
<filter object at 0x0000000002C14908>

>>> map(cube, range(1, 11))
<map object at 0x0000000002C82B70>

>>> reduce(add, range(1, 11))
Traceback (most recent call last):
  File "<pyshell#8>", line 1, in <module>
    reduce(add, range(1, 11))
NameError: name 'reduce' is not defined

これがなぜかを誰かに説明していただければ幸いです。

さらに明確にするためのコードのスクリーンショット:

Python 2と3のIDLEセッションを並べて表示


1
つまり、listだけがデータ型ではありません。リストが必要な場合は、リストが欲しいと言います。しかし、ほとんどの場合、とにかく何か他のものを欲しがります。
Veky

回答:


346

変更点については、Python 3.0の新機能を参照してください。2.xから3.xに移行するときは、多くの点が変更されているため、よくお読みください。

ここでの全体の答えは、ドキュメントからの引用です。

リストの代わりにビューとイテレータ

一部の有名なAPIはリストを返さなくなりました。

  • [...]
  • map()filter()イテレータを返します。リストが本当に必要な場合、簡単な修正はですlist(map(...))が、多くの場合、より良い修正は、リストの内包表記(特に、元のコードがラムダを使用する場合)を使用するか、コードを書き直してリストをまったく必要としないことです。map()関数の副作用のために特に注意が必要です。正しい変換は、通常のforループを使用することです(リストの作成は無駄なため)。
  • [...]

ビルトイン

  • [...]
  • 削除reduce()functools.reduce()本当に必要な場合に使用してください。ただし、99%の確率で明示的なforループが読みやすくなります。
  • [...]

21
list(map(...) どこにでも追加すると、読みやすさの向上に役立つ pythonので、関数型コンビネーターのプログレッシブ/ストリーミングアプリケーションを処理することはできません。他の言語私は行のコレクションに対してダースの操作を連鎖させることができ、それは読みやすいです。ここに?何が欲しい-入れ子になったダースの方法in??
javadba 2018

11
命令型のコンテキストで作業している場合は、for-loopがおそらくより読みやすいオプションです。しかし、機能的なコンテキストを好む十分な理由があります。そして、それから手続き型に戻るために中断することは、かなり醜い場合があります。
MatrixManAtYrService

2
@javadba「ストリーミングアプリケーション」で、list呼び出しを追加する必要があると確信していますか?「ストリーミング」の意味は「リストはまったく作成されない、次のステップに進む前に入力の各要素を完全に処理する」だと思いました。
不可解な夜

@MatrixManAtYrService Python 2の動作が必要な動作であると確信している場合は、いつでも再定義できますmap
不可解な夜

6
読みやすさの議論がそのような変化にどのようにつながるのか、私はまだ理解できません。それがパフォーマンス上の理由であったなら、私は理解するかもしれません...
港区12

86

mapおよびの機能filterは意図的に変更されてイテレータを返し、reduceは組み込みから削除され、に配置されましたfunctools.reduce

したがって、filterおよびについては、mapそれらをラップしてlist()、以前と同じように結果を確認できます。

>>> def f(x): return x % 2 != 0 and x % 3 != 0
...
>>> list(filter(f, range(2, 25)))
[5, 7, 11, 13, 17, 19, 23]
>>> def cube(x): return x*x*x
...
>>> list(map(cube, range(1, 11)))
[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]
>>> import functools
>>> def add(x,y): return x+y
...
>>> functools.reduce(add, range(1, 11))
55
>>>

ここでの推奨事項は、マップとフィルターの使用をジェネレーター式またはリスト内包表記に置き換えることです。例:

>>> def f(x): return x % 2 != 0 and x % 3 != 0
...
>>> [i for i in range(2, 25) if f(i)]
[5, 7, 11, 13, 17, 19, 23]
>>> def cube(x): return x*x*x
...
>>> [cube(i) for i in range(1, 11)]
[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]
>>>

forループは、reduceよりも読みやすい時間の99%であると言われていますが、私はに固執しfunctools.reduceます。

編集:99%の数値は、Guido van Rossumが作成したPython 3.0の新機能のページから直接引用されています。


5
リスト内包表記に追加の関数を作成する必要はありません。使用するだけ[i*i*i for i in range(1,11)]
シャオ

2
あなたは絶対的に正しいです。関数をリスト内包表記の例に含めて、フィルター/マップの例と同様に見えるようにしました。
ジョシュアD.ボイド

5
i ** 3もi * i * iと同等です
Breezer

5
@Breezerは実際i**3にはi.__pow__(3)and i*i*i i.__mul__(i).__mul__(i)(またはそのようなもの)を呼び出します。intの場合は問題ありませんが、numpyの数値やカスタムクラスの場合、結果が異なる場合さえあります。
同義語2016年

1
「ガイドが決定Xを下した」と聞くたびに、その痛みは起こりそうな結果であることに気づきました。これは良い例です。Pythonですでに冗長list(list(list(.. )))だったものを実行するためです。
javadba 2018年

12

他の回答の補足として、これは、これらの関数の名前をリストを返すものに再マッピングreduceし、グローバル名前空間に導入するコンテキストマネージャーの優れたユースケースのように聞こえます。

簡単な実装は次のようになります。

from contextlib import contextmanager    

@contextmanager
def noiters(*funcs):
    if not funcs: 
        funcs = [map, filter, zip] # etc
    from functools import reduce
    globals()[reduce.__name__] = reduce
    for func in funcs:
        globals()[func.__name__] = lambda *ar, func = func, **kwar: list(func(*ar, **kwar))
    try:
        yield
    finally:
        del globals()[reduce.__name__]
        for func in funcs: globals()[func.__name__] = func

次のような使用法の場合:

with noiters(map):
    from operator import add
    print(reduce(add, range(1, 20)))
    print(map(int, ['1', '2']))

どのプリント:

190
[1, 2]

ちょうど私の2セント:-)


1
python言語が混乱しているよう-しかし、それは優秀なライブラリへのV優れていますnumpypandasstatsmodels、友人を..私はあなたが母国語の痛みを軽減するためにここに表示さのような便利なライブラリをbulidingされていた-しかし、エネルギーを失っていないにしてみてくださいしています遠くから浮遊data.frame/ datatable、またはxarray。しかし、試してみてください..
javadba

7

reduceメソッドはPython3の組み込み関数から削除されているため、functoolsコードにをインポートすることを忘れないでください。以下のコードスニペットをご覧ください。

import functools
my_list = [10,15,20,25,35]
sum_numbers = functools.reduce(lambda x ,y : x+y , my_list)
print(sum_numbers)

2

以下は、フィルター、マップ、およびリデュース関数の例です。

数値= [10,11,12,22,34,43,54,34,67,87,88,98,99,87,44,66]

//フィルタ

oddNumbers = list(filter(lambda x:x%2!= 0、numbers))

print(oddNumbers)

//地図

multiplyOf2 = list(map(lambda x:x * 2、numbers))

print(multiplyOf2)

//減らす

一般に使用されていないため、reduce関数はPython 3の組み込み関数から削除されました。functoolsモジュールで引き続き使用できるため、次のことができます。

functools import reduceから

sumOfNumbers = reduce(lambda x、y:x + y、numbers)

print(sumOfNumbers)


0

map、filter、reduceの利点の1つは、複雑なものを実行するためにそれらを "チェーン"したときにどれほど読みやすくなるかです。ただし、組み込みの構文は判読できず、すべて「逆方向」です。だから、私はPyFunctionalパッケージ(https://pypi.org/project/PyFunctional/ます2つの比較を以下に示します。

flight_destinations_dict = {'NY': {'London', 'Rome'}, 'Berlin': {'NY'}}

PyFunctionalバージョン

非常に読みやすい構文。あなたは言うことができます:

「一連のフライトの目的地があります。市がdict値にある場合は、そのうちからdictキーを取得します。最後に、プロセスで作成した空のリストをフィルターで除外します。」

from functional import seq  # PyFunctional package to allow easier syntax

def find_return_flights_PYFUNCTIONAL_SYNTAX(city, flight_destinations_dict):
    return seq(flight_destinations_dict.items()) \
        .map(lambda x: x[0] if city in x[1] else []) \
        .filter(lambda x: x != []) \

デフォルトのPythonバージョン

それはすべて後方です。あなたは言う必要があります:

「それで、リストがあります。空のリストをフィルターで除外します。なぜですか?都市がdict値にある場合、最初にdictキーを取得したからです。ああ、これを行っているリストは、flight_destinations_dictです。 」

def find_return_flights_DEFAULT_SYNTAX(city, flight_destinations_dict):
    return list(
        filter(lambda x: x != [],
               map(lambda x: x[0] if city in x[1] else [], flight_destinations_dict.items())
               )
    )
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.