使用reduce()在lambda函数中使用math.factorial

时间:2011-09-26 19:33:29

标签: python lambda permutation reduce factorial

我正在尝试编写一个函数来计算字符串的唯一排列数。例如aaa将返回1abc将返回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)

一切正常,除非我尝试传递一个只有一个唯一字符的字符串,即aaa - 我得错了答案:

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

现在,我可以告诉问题是在长度为1的列表中运行带有阶乘的lambda函数。但我不知道为什么。大多数其他lambda函数在长度为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 个答案:

答案 0 :(得分:2)

请参阅reduce()的文档,有一个可选的'initializer'参数放在列表中的所有其他元素之前,以便一个元素列表的行为是一致的,例如,对于{{1你可以将ord()设置为initializer为0的字符:

ord()

答案 1 :(得分:1)

Python的reduce函数并不总是知道默认(初始)值应该是什么。应该有一个采用初始值的版本。提供合理的初始值,reduce应该可以很好地工作。

另外,根据评论,您可能只需在lambda中的第二个参数上使用factorial

reduce(lambda x,y: x * factorial(y), lst, 1)

答案 2 :(得分: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])

答案 3 :(得分:0)

通过首先计算序列中前两个元素的结果来减少工作,然后从那里伪递归地跟随。大小为1的列表是一种特殊情况。

我会在这里使用列表理解:

prod( [ factorial(val) for val in lst ] )
祝你好运!