2.7.6

2015-02-08 76 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[:]