Python递归列表

时间:2017-11-04 20:10:23

标签: python algorithm backtracking

我很难理解Python在下面的情况下是如何工作的。

我以递归方式计算列表的所有排列,并且我想返回包含所有这些排列的列表列表。代码工作正常,如果我只是打印出来,但如果我尝试扩展最终[结果]我最终得到一个列表与我的输入列表相同的值(抱歉重复单词列表)

这是我的代码:

def swap(l, i, j):
  l[i], l[j] = l[j], l[i]

def compute(l):
  if not len(l):
    print 'no list'
  start, end = 0, len(l) - 1
  return _compute(l, start, end)

def _compute(l, start, end):
  res = []
  if start == end:
    return [l]
  else:
    for i in range(start, end+1):
      swap(l, start, i)
      res.extend(_compute(l, start+1, end))
      swap(l, start, i) # backtrack
  return res

l = [1,2,3]
print compute(l)

结果:

[[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]]

就像我说的,如果我打印出结果,它会按预期工作:

def swap(l, i, j):
  l[i], l[j] = l[j], l[i]

def compute(l):
  if not len(l):
    print 'no list'
  start, end = 0, len(l) - 1
  _compute(l, start, end)


def _compute(l, start, end):
  if start == end:
    print l
  else:
    for i in range(start, end+1):
      swap(l, start, i)
      _compute(l, start+1, end)
      swap(l, start, i) # backtrack

l = [1,2,3]

compute(l)

输出:

[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 2, 1]
[3, 1, 2]

为什么?

1 个答案:

答案 0 :(得分:1)

Python使用对象。变量指的是对象。如果将列表添加到结果列表中,然后进行修改,结果中的列表将反映这些更改。

因此,您应该至少制作副本。例如,您可以使用:

def _compute(l, start, end):
  res = []
  if start == end:
    return [l[:]]  # make a shallow copy
  else:
    for i in range(start, end+1):
      swap(l, start, i)
      res.extend(_compute(l, start+1, end))
      swap(l, start, i) # backtrack
  return res

l = [1,2,3]
print compute(l)

然而,这段代码片段效率仍然很低,而且难以理解。请注意,not(len(l))不会检查对象是否有len(..):它会检查len(l)是否为零。因此,您应该使用isinstance(..)

更有效的方法是构造res列表一次,并将其传递给系统集合结果。例如:

def _compute(l):
  def _calc(start, end, res):
    if start < end-1:
        for i in range(start,end):
          swap(l,start,i)
          _calc(start+1, end, res)
          swap(l,start,i)
    else:
      res.append(l[:])
    return res
  return _calc(0, len(l), [])