1

文字列の一意の順列の数を計算する関数を作成しようとしています。たとえば、aaareturn1abcreturn を返し6ます。
私はこのような方法を書いています:

(疑似コード:)

len(string)! / (A!*B!*C!*...) 

ここで、A、B、C はそれぞれの固有文字の出現回数です。たとえば、文字列'aaa'は になりますが3! / 3! = 1、 に'abc'なります3! / (1! * 1! * 1!) = 6

これまでの私のコードは次のようなものです:

def permutations(n):
    '''
    returns the number of UNIQUE permutations of n
    '''
    from math import factorial

    lst = []
    n = str(n)
    for l in set(n):
        lst.append(n.count(l))

    return factorial(len(n)) / reduce(lambda x,y: factorial(x) * factorial(y), lst)

一意の文字が 1 つしかない文字列を渡そうとした場合を除いて、すべて正常に動作します。つまりaaa、間違った答えが得られます。

>>> perm('abc')
6
>>> perm('aaa')
2
>>> perm('aaaa')
6

ここで、長さ 1 のリストに対して階乗を使用してラムダ関数を実行することに問題があることがわかります。ただし、その理由はわかりません。他のほとんどのラムダ関数は、2 つの要素が必要な場合でも、長さ 1 のリストで機能します。

>>> reduce(lambda x,y: x * y, [3])
3
>>> reduce(lambda x,y: x + y, [3])
3

これはしません:

>>> reduce(lambda x,y: ord(x) + ord(y), ['a'])
'a' 
>>> reduce(lambda x,y: ord(x) + ord(y), ['a','b'])
195

私が別のことをしなければならないことはありますか?これを回避するさまざまな方法で関数を書き直すことができることはわかっていますが (たとえば、 を使用しないlambda)、これが具体的に機能しない理由を探しています。

4

4 に答える 4

2

のドキュメントを参照してください。reduce()オプションの「initializer」引数がリスト内の他のすべての要素の前に配置されるため、1つの要素リストの動作が一貫します。たとえば、ord()ラムダの場合initializerord()0:

>>> reduce(lambda x, y: ord(x) + ord(y), ['a'], chr(0))
97
于 2011-09-26T19:46:50.163 に答える
1

必要に応じlen(s)! / A!*B!*C!て、の使用はreduce()機能しません。計算されるためfactorial(factorial(A)*factorial(B))*factorial(C)です。言い換えれば、それは本当に可換であるための操作を必要とします。

代わりに、階乗のリストを生成してから、それらを乗算する必要があります。

import operator
reduce(operator.mul, [factorial(x) for x in lst])
于 2011-09-26T19:46:08.980 に答える
1

Pythonのreduce関数は、デフォルト(初期)値がどうあるべきかを常に知っているわけではありません。初期値を取るバージョンがあるはずです。賢明な初期値を提供すれば、reduce美しく機能するはずです。

また、コメントから、factorialラムダの2番目の引数で使用する必要があります。

reduce(lambda x,y: x * factorial(y), lst, 1)
于 2011-09-26T19:39:30.077 に答える
0

Reduce は、最初にシーケンスの最初の 2 つの要素の結果を計算し、そこから疑似再帰的に実行することによって機能します。サイズ 1 のリストは特殊なケースです。

ここではリスト内包表記を使用します。

prod( [ factorial(val) for val in lst ] )

幸運を!

于 2011-09-26T19:40:15.623 に答える