1

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

4 回答 4

2

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

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

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

此外,从评论中,您可能应该只使用factoriallambda 中的第二个参数:

reduce(lambda x,y: x * factorial(y), lst, 1)
于 2011-09-26T19:39:30.077 回答
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 回答
0

Reduce 的工作原理是首先计算序列中前两个元素的结果,然后从那里进行伪递归。大小为 1 的列表是一种特殊情况。

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

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

祝你好运!

于 2011-09-26T19:40:15.623 回答