2.7.6

2015-02-08 25 views
0

我最近一直在与一些代码,最近这涉及一个迭代打转转:2.7.6

"""IntegerPartitions.py 

Generate and manipulate partitions of integers into sums of integers. 

D. Eppstein, August 2005. 

https://www.ics.uci.edu/~eppstein/PADS/IntegerPartitions.py 
""" 

def mckay(n): 
    """ 
    Integer partitions of n, in reverse lexicographic order. 
    The output and asymptotic runtime are the same as mckay(n), 
    but the algorithm is different: it involves no division, 
    and is simpler than mckay, but uses O(n) extra space for 
    a recursive call stack. 
    """ 
    if n == 0: 
     yield [] 
    if n <= 0: 
     return 
    for p in mckay(n-1): 
     if len(p) == 1 or (len(p) > 1 and p[-1] < p[-2]): 
      p[-1] += 1 
      yield p 
      p[-1] -= 1 
     p.append(1) 
     yield p 
     p.pop() 

该方案需要一个整数,并返回发生器输出该整数的分区。

但是,当我尝试在代码中使用它时,我发现有些奇怪的东西。

>>> p = mckay(4) 
>>> print list(p) 
[[], [], [], [], []] 
>>> q = mckay(4) 
>>> cumulator = [] 
>>> for x in q : 
...  cumulator.append(x) 
>>> print cumulator 
[[], [], [], [], []] 
>>> print list(mckay(4)) 
[[], [], [], [], []] 
>>> r = mckay(4) 
>>> for x in r : 
...  print x 
[4] 
[3, 1] 
[2, 2] 
[2, 1, 1] 
[1, 1, 1, 1] 
>>> for x in mckay(4) : 
...  print x 
[4] 
[3, 1] 
[2, 2] 
[2, 1, 1] 
[1, 1, 1, 1] 

除非我逐一打印,否则分区似乎不会显示出来。这是一个语言中的错误(我的版本是Ubuntu Trusty上的Python 2.7.6),还是有我缺少的东西?我在Google上四处浏览,似乎无法找到与此相关的任何内容。

我认为它可能有一些做的递归调用,但我用下面的代码试了一下,发现了类似的结果

def mckay(n): 
    """ 
    Integer partitions of n, in reverse lexicographic order. 
    Note that the generated output consists of the same list object, 
    repeated the correct number of times; the caller must leave this 
    list unchanged, and must make a copy of any partition that is 
    intended to last longer than the next call into the generator. 
    The algorithm follows Knuth v4 fasc3 p38 in rough outline. 
    """ 
    if n == 0: 
     yield [] 
    if n <= 0: 
     return 
    partition = [n] 
    last_nonunit = (n > 1) - 1 
    while True: 
     yield partition 
     if last_nonunit < 0: 
      return 
     if partition[last_nonunit] == 2: 
      partition[last_nonunit] = 1 
      partition.append(1) 
      last_nonunit -= 1 
      continue 
     replacement = partition[last_nonunit] - 1 
     total_replaced = replacement + len(partition) - last_nonunit 
     reps,rest = divmod(total_replaced,replacement) 
     partition[last_nonunit:] = reps*[replacement] 
     if rest: 
      partition.append(rest) 
     last_nonunit = len(partition) - (partition[-1]==1) - 1 

的结果几乎是一致的:

>>> p = mckay(4) 
>>> print list(p) 
[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]] 
>>> q = mckay(4) 
>>> cumulator = [] 
>>> for x in q : 
...  cumulator.append(x) 
>>> print cumulator 
[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]] 
>>> print list(mckay(4)) 
[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]] 
>>> r = mckay(4) 
>>> for x in r : 
...  print x 
[4] 
[3, 1] 
[2, 2] 
[2, 1, 1] 
[1, 1, 1, 1] 
>>> for x in mckay(4) : 
...  print x 
[4] 
[3, 1] 
[2, 2] 
[2, 1, 1] 
[1, 1, 1, 1] 

回答

2

问题是功能mckay正在修改相同的列表对象,所以当你调用list()时,你实际上会得到一个包含4个实际指向同一个对象的项目的列表。所以,最后列表对象是空的,所有你得到的是列表与空列表。

>>> p = mckay(4) 
>>> [id(x) for x in p] 
[139854369904832, 139854369904832, 139854369904832, 139854369904832, 139854369904832] 

>>> for x in mckay(4): 
    print x, '-->', id(x) 

[4] --> 140446845125552 
[3, 1] --> 140446845125552 
[2, 2] --> 140446845125552 
[2, 1, 1] --> 140446845125552 
[1, 1, 1, 1] --> 140446845125552 
>>> x # The actual list object is empty at the end of the iteration 
[] 
>>> id(x) 
140446845125552 

但是当你遍历它你只是简单的打印返回的对象立即因此不同的输出,这里一个解决办法是产生浅拷贝:

yield p[:] 
相关问题