【问题标题】:Recursive list comprehension for permutation. Python用于排列的递归列表理解。 Python
【发布时间】:2013-04-16 07:14:08
【问题描述】:

我在 python 中有一个函数,它是在列表理解中递归编程的。但我不清楚它到底发生了什么!

def permut(s,l):
    if l == []: return [[s]]
    return [ e + [l[0]] for e in permut(s, l[1:])] + [l+[s]]

该函数有两个参数,第一个是字符串,第二个是列表,它返回列表中字符串的排列。

permut('a', [1,2,3])
[['a', 3, 2, 1], [3, 'a', 2, 1], [2, 3, 'a', 1], [1, 2, 3, 'a']]

谁能解释一下,列表理解中会发生什么?

【问题讨论】:

  • 递归调用中的 a 是什么?
  • 是的,你是对的 Tim P.
  • 你真正想做什么?是你自己的代码吗?如果没有,你是想解决它的问题,还是简单地理解它?
  • 我想了解一下,列表推导到底发生了什么?

标签: python recursion list-comprehension


【解决方案1】:

如果列表解析语法让你失望,你可以重写这个函数,并在此过程中添加一些调试print()s:

def permut(s,l):
    print("Entering function permut()")
    print("Parameters:\ns: {}\nl: {}".format(s,l))
    if l == []: 
        print("End of recursion reached, returning {}".format([[s]]))
        return [[s]]
    result = []
    for e in permut(s, l[1:]):
        result.append(e + [l[0]])
    result += [l + [s]]
    print("Returning {}".format(result))
    return result

这是你得到的输出:

>>> permut('a', [1,2,3])
Entering function permut()
Parameters:
s: a
l: [1, 2, 3]
Entering function permut()
Parameters:
s: a
l: [2, 3]
Entering function permut()
Parameters:
s: a
l: [3]
Entering function permut()
Parameters:
s: a
l: []
End of recursion reached, returning [['a']]
Returning [['a', 3], [3, 'a']]
Returning [['a', 3, 2], [3, 'a', 2], [2, 3, 'a']]
Returning [['a', 3, 2, 1], [3, 'a', 2, 1], [2, 3, 'a', 1], [1, 2, 3, 'a']]
[['a', 3, 2, 1], [3, 'a', 2, 1], [2, 3, 'a', 1], [1, 2, 3, 'a']]

【讨论】:

  • 不是真的,什么总是把变量 e 作为一个值??
  • @T.C.它迭代permut(s, l[1:])的返回值,这意味着首先是['a', 3, 2, 1],然后是[3, 'a', 2, 1],...(使用您在问题中提供的示例)
【解决方案2】:

首先,在递归 permut 调用中,您使用的是 a 而不是 s。

return [ e + [l[0]] for e in permut(a, l[1:])] + [l+[s]]

首先,它计算permut(s, l[1:]),即:尝试置换s和列表中没有第一个元素的部分。只要有任何元素,它就会丢弃第一个元素,然后递归调用返回 [[s]]。

现在,在调用中倒退,s 被“添加”到递归创建的列表的每个元素中,然后给定 l 被附加,结果是:

# l == []
return [['a']]

# e == ['a']
# l == [3], l[0] == 3
return [['a'] + [3]] + [[3] + [a]]
# equals [['a', 3], [3, 'a']]

# e == ['a', 3] then [3, 'a']
# l == [2, 3], l[0] == 2
return [['a', 3] + [2], [3, 'a'] + [2]] + \
        [[2, 3] + [a]]
# equals [['a', 3, 2], [3, 'a', 2], [2, 3, 'a']]

# e == ['a', 3, 2] then [3, 'a', 2] then [2, 3, 'a']
# l == [1, 2, 3], l[0] == 1
return [['a', 3, 2] + [1], [3, 'a', 2] + [1], [2, 3, 'a'] + [1]] + \
        [[1, 2, 3] + ['a']]
# equals [['a', 3, 2, 1], [3, 'a', 2, 1], [2, 3, 'a', 1], [1, 2, 3, 'a']]

也许它读起来并不漂亮,但它确实有效。您可以看到e 被提取为上一级返回列表的单个元素。

你也可以试试:

def tee(parm):
    print parm
    return parm

并将permut重新定义为:

def permut(s,l):
    if l == []: return [[s]]
    return [ e + [l[0]] for e in tee(permut(s, l[1:]))] + [l+[s]]

我的输出:

[['a']]
[['a', 3], [3, 'a']]
[['a', 3, 2], [3, 'a', 2], [2, 3, 'a']]
[['a', 3, 2, 1], [3, 'a', 2, 1], [2, 3, 'a', 1], [1, 2, 3, 'a']]

其中包括递归调用。

【讨论】:

  • 计算permut('a', [1, 2, 3])permut('a', [2, 3])需要先计算。其中,permut('a', [3]) 被调用,它调用permut('a', [])。这样,permut('a', []) 是第一个调用,它拥有返回值所需的一切,因此它将它返回到更高级别,这反过来也能够计算返回值 - 所以它继续 - 在调用中前进, 向后返回结果。不过,使用“尾递归”可以不倒退 - 我鼓励您探索这个主题(尽管它与 Python 不太相关)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-10
  • 2020-10-17
  • 2012-10-18
  • 2016-06-19
  • 2021-12-01
相关资源
最近更新 更多