python - 使用另一个 python 生成器对生成的数字进行排序

标签 python sorting generator

我正在尝试使用 python 生成器实现一种合并排序,以在生成的数字中找到最小数字并生成下一个数字,这是我的示例代码:

class GeneratorSort():
    def __init__(self, *args):
        self.values = [(arg.next(), i) for i, arg in enumerate(args)]
        self.generators = args

    def generate(self):
        r, index = min(self.values)
        self.values[index] = self.generators[index].next()
        yield r


def t(l):
    for each in l:
        yield each

l1 = [2, 5, 6, 8]
l2 = [1, 4, 5, 7]
l3 = [0, 3, 9, 10]

a = GeneratorSort(t(l1), t(l2), t(l3))

但是当我尝试打印排序结果时,我只得到了 0 并且下一次出现错误:

>>> for i in a.generate():
        print i
0

这里是错误:

>>> a.generate()
<generator object generate at 0x7fa7bcc37a00>
>>> a.generate().next()

Traceback (most recent call last):
  File "<pyshell#1>", line 1, in <module>
    a.generate().next()
  File "/home/hamid/projects/bfl/workspace/testo.py", line 10, in generate
    r, index = min(self.values)
TypeError: 'int' object is not iterable
>>> 

我希望从这个函数中打印出像 1,2,3,4,5 和 ... 已排序。还有其他办法吗?

请注意,我需要使用生成器。

最佳答案

您正在用以下值替换您的(value, index) 元组:

self.values[index] = self.generators[index].next()

你需要用一个新的元组替换它:

self.values[index] = (self.generators[index].next(), index)

否则迭代赋值失败;您不能将一个 int 分配给两个变量。

您的生成器缺少循环和空生成器处理:

def generate(self):
    while any(self.values):
        r, index = min(v for v in self.values if v)
        try:
            self.values[index] = (self.generators[index].next(), index)
        except StopIteration:
            self.values[index] = None
        yield r

这会将您的 self.values 列表的元素设置为 None 以指示可迭代对象已用完。这不是处理这种边缘情况的最有效方法;在version I wrote before我使用字典来跟踪事件的可迭代对象,并简单地从中删除以保持索引(键)稳定。

请注意,您可以使用内置的 iter() function 替换 t() 函数.

演示:

>>> class GeneratorSort():
...     def __init__(self, *args):
...         self.values = [(arg.next(), i) for i, arg in enumerate(args)]
...         self.generators = args
...     def generate(self):
...         while any(self.values):
...             r, index = min(v for v in self.values if v)
...             try:
...                 self.values[index] = (self.generators[index].next(), index)
...             except StopIteration:
...                 self.values[index] = None
...             yield r
... 
>>> l1 = [2, 5, 6, 8]
>>> l2 = [1, 4, 5, 7]
>>> l3 = [0, 3, 9, 10]
>>> a = GeneratorSort(iter(l1), iter(l2), iter(l3))
>>> list(a.generate())
[0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 10]

标准库使用 heapq.merge() function 可以更有效地完成它;它使用堆以非常有效的方式按最低值对可迭代对象进行排序; min() 需要遍历所有 K 个可迭代对象,而使用堆只需要 log-K 步来保持堆不变性。

>>> import heapq
>>> list(heapq.merge(l1, l2, l3))
[0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 10]

可以研究source code ,已针对最佳性能进行了高度调整。

关于python - 使用另一个 python 生成器对生成的数字进行排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28647371/

相关文章:

python - 从 Matlab 运行 python 脚本 - 无法加载 matplotlib

python - 以编程方式查找 'spike' 或放入数据集

python 获取所有使用套接字打开的文件描述符

python - 如何按属性的属性对查询集进行排序? Django

Python - 有什么方法可以在子函数中组织一组 yield 以在 main 函数之外产生?

python - RNN 在 TensorFlow 中的实时实现

sorting - 优化redis排序集内存使用

.net - SSRS 2008 - 组内排序

python - 将生成器包装为单个 `next` 调用,而不是两个步骤( __iter__ + __next__ )

python : Generating cyclic permutations code (An unexpected code error to be clarified)