繁体   English   中英

有理数发生器(Python)

[英]Rational number generator (Python)

  1. 为什么要删除[1,3],[3,2]条目并替换为[2,3],[3,1]?

  2. 请注意,[2,3],[3,1]是正确的分支,但不应覆盖先前的条目,而应将其附加到其后。

     def rational(): treecount = 0 tree = [[[1,1]]] left=[0,0] right=[0,0] while(True): treecount+=1 tree.append([]) left=[0,0] right=[0,0] for z in range(len(tree[treecount-1])): left[0] = tree[treecount-1][z][0] right[0] = tree[treecount-1][z][0] + tree[treecount-1][z][1] left[1] = tree[treecount-1][z][1] + tree[treecount-1][z][0] right[1] = tree[treecount-1][z][1] tree[treecount].append(left) tree[treecount].append(right) yield( tree) 

输出看起来像这样:

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

您正在遇到Python对象模型的一个基本方面,即Python永远不会隐式地创建对象的副本。

在代码中,您将创建两个新的列表leftright刚刚进入之前for循环。 然后,您反复修改这两个列表,并将它们附加到树上。 没关系,除了您要做的就是重复将引用附加到相同的两个列表中。

这是此现象的一个简单示例。 我们将在left创建一个列表,然后将其追加到另一个outer列表:

>>> outer = []
>>> left = [1, 3]
>>> outer.append(left)
>>> outer
[[1, 3]]

到目前为止,一切都很好:一切都按预期进行。 但是现在让我们left修改并再次将其附加到outer

>>> left[0] = 4
>>> outer.append(left)
>>> outer
[[4, 3], [4, 3]]

请注意outer的第一个条目如何更改? 这是因为outer目前不包含两个独立的列表:相反,它包含对同一列表的两个引用。 这就是上面的代码中发生的事情。

它的简单修复:创建leftright重新每个的迭代for循环:

for z in range(len(tree[treecount-1])):
    left=[0, 0]
    right=[0, 0]
    left[0] = tree[treecount-1][z][0]
    right[0] = tree[treecount-1][z][0] + tree[treecount-1][z][1]
    left[1] = tree[treecount-1][z][1] + tree[treecount-1][z][0]
    <and so on>

或者,你可以让副本leftright附加在他们面前:

tree[treecount].append(list(left))
tree[treecount].append(list(right))

顺便说一句,如果更好地利用Python的一些惯用法,则可以大大简化代码。 首先,通常不需要在range(len(something))迭代,尤其是当您要直接使用这些值作为索引时。 而是直接在列表上进行迭代。 其次,您可以直接在for语句中解压tree[treecount-1]值。 然后,您可以使用负索引从列表末尾开始索引,从而无需维护treecount 进行了这些首过更改后,您的代码如下所示:

def rational():
    tree = [[[1,1]]]
    while True:
        tree.append([])
        for a, b in tree[-2]:
            left = [a, b + a]
            right = [a + b, b]
            tree[-1].extend([left, right])
            yield tree

仍有改进的空间,但这已经比原始代码更具可读性。

如果您实际上不需要树,而只是想遍历积极的理性,则可以使用此生成器。 输出与Calkin-Wilf树的广度优先遍历顺序相同,但无需增加队列的开销。

from fractions import Fraction
def Calkin_Wilf():
   x = Fraction(1, 1)
   yield x
   while True:
      x = Fraction(1, 2*Fraction(int(x))-x+1)
      yield x

使用生成器创建一个迭代器,然后使用next()进行迭代,例如:

rational = Calkin_Wilf()
for _ in range(100):
   print(next(rational))

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM