【问题标题】:Using math.factorial in a lambda function with reduce()在带有 reduce() 的 lambda 函数中使用 math.factorial
【发布时间】:2011-11-25 11:50:56
【问题描述】:

我正在尝试编写一个函数来计算字符串的唯一排列数。例如,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),但我正在寻找为什么这特别不起作用。

【问题讨论】:

    标签: python lambda permutation reduce factorial


    【解决方案1】:

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

    此外,在 cmets 中,您可能应该只在 lambda 的第二个参数上使用 factorial

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

    【讨论】:

    • @agf & Platinum Azure - 谢谢,这适用于大小为 1 的列表,但任何更大的都失败。为什么?文档似乎说应该将初始值视为列表只是长一个元素。
    • 你可以试试reduce(lambda x,y: x * factorial(y), lst, 1)。您计算的 lambda 类似于 ((1! * 2!)! * 3!)! ...
    • 你确定你应该在第一个参数上使用factorial(x) 吗?如果你想要所有阶乘的乘积,你应该使用reduce(lambda x,y: x * factorial(y), lst, 1)
    • @cHao & Platinum Azure。谢谢!那确实解决了它。
    【解决方案2】:

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

    >>> reduce(lambda x, y: ord(x) + ord(y), ['a'], chr(0))
    97
    

    【讨论】:

      【解决方案3】:

      如果您想要len(s)! / A!*B!*C!,那么使用reduce() 将不起作用,因为它将计算factorial(factorial(A)*factorial(B))*factorial(C)。换句话说,它确实需要操作是可交换的。

      相反,您需要生成阶乘列表,然后将它们相乘:

      import operator
      reduce(operator.mul, [factorial(x) for x in lst])
      

      【讨论】:

        【解决方案4】:

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

        我会在这里使用列表推导:

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

        祝你好运!

        【讨论】:

          猜你喜欢
          • 2021-12-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-11-12
          • 1970-01-01
          • 2018-05-31
          • 2017-06-03
          相关资源
          最近更新 更多