2012-02-02 28 views
27

私が理解している限り、reduce関数はリストlと関数をとります。次に、リストの最初の2つの要素の関数fを呼び出し、次のリスト要素と前の結果を持つ関数fを繰り返し呼び出します。機能の削減はどのように機能しますか?

だから、私は次の関数を定義します。

次の関数は階乗を計算します。

def fact(n): 
    if n == 0 or n == 1: 
     return 1 
    return fact(n-1) * n 


def reduce_func(x,y): 
    return fact(x) * fact(y) 

lst = [1, 3, 1] 
print reduce(reduce_func, lst) 

これは私にはありません((1! * 3!) * 1!) = 6?しかし、代わりに720となります。なぜ720ですか?それは6の階乗もとるようです。しかし、私はなぜそれを理解する必要があります。

誰かがこれが起こる理由と回避策を説明できますか?

基本的には、リスト内のすべての項目の階乗の積を計算したいと考えています。 バックアップ計画は、ループを実行して計算することです。しかし、私はreduceを使うのが好きです。

+0

ありがとうございます。私は逃したばかげたことを理解しました。そして私は答えでこれを行う正しい方法を投稿しました。 – Divya

+0

* reduce *についてより深く理解するには、以下に示す純粋なpythonの同等機能を参照してください。 –

答えて

0

OK]をクリックして、それを得た:

私が最初に彼らの階乗に番号をマッピングして、乗算演算子で減らす呼び出す必要があります。

ので、これは動作します:

lst_fact = map(fact, lst) 
reduce(operator.mul, lst_fact) 
+0

さて、それは仕事の並べ替えだろう。あなたの階乗関数はまだその入力の階乗を計算しているので、単純に減算するのではありません。 – Marcin

+0

はい、これを行う方法の1つで、factorial計算をreduce関数の中に置くよりも、クリーンな方がいいでしょう。しかし、どちらか一方があなたの望むことをするでしょう。 –

9

あなたの関数は、の両方の引数のfact()を呼び出します。 ((1! * 3!)! * 1!)と計算されています。この問題を回避するのみだけ第二引数でそれを呼び出し、reduce()Python reduce documentation 1.

7

の初期値を渡し、

(関数、配列)を低減呼び出すことによって構築単一の値を返すですシーケンスの最初の2つの項目に対して(バイナリ)関数を実行し、次に結果と次の項目に続きます。

だから、ステップスルー。最初の2つの要素のreduce_funcreduce_func(1, 3) = 1! * 3! = 6を計算します。次に、結果のreduce_funcと次の項目:reduce_func(6, 1) = 6! * 1! = 720を計算します。

最初のreduce_funcコールの結果が2番目の入力に渡されると、それは乗算の前に階乗されます。

0

まあ、すべての最初の、あなたのreduce_funcは折り畳みの構造を持っていません。折りたたみの説明に一致しません(これは正しい)。

倍の構造は次のとおりです。

def foldl(func, start, iter): return func(start, foldl(func, next(iter), iter)今、あなたのfact関数は、2つの要素に動作しない - それはちょうど階乗を計算します。

したがって、あなたはフォールドを使用していないので、その階乗の定義では、あなたは必要ありません。

あなたは、Yコンビネータをチェックし、階乗で遊ん化したいなら:http://mvanier.livejournal.com/2897.html

あなたは折り目について学びたいのであれば、この質問に対する私の答えを見て、累積画分を計算するためのその使用方法を示しています:creating cumulative percentage from a dictionary of data

25

(削減を理解する最も簡単な方法)その純粋なPythonの同等のコードを見ることである。

def myreduce(func, iterable, start=None): 
    it = iter(iterable) 
    if start is None: 
     try: 
      start = next(it) 
     except StopIteration: 
      raise TypeError('reduce() of empty sequence with no initial value') 
    accum_value = start 
    for x in iterable: 
     accum_value = func(accum_value, x) 
    return accum_value 

あなたはそれを見ることができますそれが唯一の右端の引数に階乗を適用するために、あなたのreduce_func()のために理にかなって:

def fact(n): 
    if n == 0 or n == 1: 
     return 1 
    return fact(n-1) * n 

def reduce_func(x,y): 
    return x * fact(y) 

lst = [1, 3, 1] 
print reduce(reduce_func, lst) 

その小さな改正では、コードがあなたが:-)

+0

あなたはちょうど 'reduce'を裸にしました! 'start = None'が' myreduce((lambda x、y:x + y)、[1,2,3,4]) 'でないときは11を返します。私は 'func'として' sum'を取った。 – SIslam

+0

修正は 'iterable [1:]の' for x 'のようにするべきだと思います: – SIslam

+0

forループは 'iterable'ではなく' it'を反復すべきです: 'for x in it:' – vaerek

0

ます。また、実装することができ、予想通り生成します減法を用いた階乗。

def factorial(n): 
    return(reduce(lambda x,y:x*y,range(n+1)[1:])) 
38

他の回答は素晴らしいです。私は単に私がreduce()を理解するためにかなり良い見つけることを図示した例を追加します:次のように

>>> reduce(lambda x,y: x+y, [47,11,42,13]) 
113 

が計算されます。

enter image description here

Source)(mirror

+1

そこに行きます。ありがとうございました! –

0

を削減しますパラメータ#2のイテレータによって提供される値を介してパラメータ#1の関数を連続して実行する

print '-------------- Example: Reduce(x + y) --------------' 

def add(x,y): return x+y 
x = 5 
y = 10 

import functools 
tot = functools.reduce(add, range(5, 10)) 
print 'reduce('+str(x)+','+str(y)+')=' ,tot 

def myreduce(a,b): 
    tot = 0 
    for i in range(a,b): 
     tot = tot+i 
     print i,tot 
    print 'myreduce('+str(a)+','+str(b)+')=' ,tot 

myreduce(x,y) 

print '-------------- Example: Reduce(x * y) --------------' 

def add(x,y): return x*y 
x = 5 
y = 10 

import functools 
tot = functools.reduce(add, range(5, 10)) 
print 'reduce('+str(x)+','+str(y)+')=' ,tot 

def myreduce(a,b): 
    tot = 1 
    for i in range(a,b): 
     tot = tot * i 
     print i,tot 
    print 'myreduce('+str(a)+','+str(b)+')=' ,tot 

myreduce(x,y) 
関連する問題