[英]Sort generated numbers using another python generator
I'm trying to implement kind of merge sort using a python generator to find the minimum number among generated numbers and generate the next one and here is my sample code: 我正在尝试使用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))
But when I try to print sort results I got only 0
and next time an error: 但是当我尝试打印排序结果时,我只得到
0
并且下次出错:
>>> for i in a.generate():
print i
0
And here is the error: 这是错误:
>>> 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
>>>
I expect from this function to print numbers like 1
, 2
, 3
, 4
, 5
and ... sorted. 我从这个函数期望打印号码,如
1
, 2
, 3
, 4
, 5
和......排序。 Is there any other way? 还有其他方法吗?
Notice that I need the use of generators. 请注意,我需要使用生成器。
You are replacing your (value, index)
tuples with just the value: 要更换你的
(value, index)
只值的元组:
self.values[index] = self.generators[index].next()
You need to replace that with a new tuple: 您需要用新元组替换它:
self.values[index] = (self.generators[index].next(), index)
otherwise the iterable assignment fails; 否则可迭代的赋值失败; you cannot assign one
int
to two variables. 你不能将一个
int
分配给两个变量。
Your generator is missing a loop and handling of empty generators: 您的生成器缺少循环并处理空生成器:
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
This sets elements of your self.values
list to None
to indicate the iterable has been exhausted. 这
self.values
列表的元素设置为None
以指示iterable已用尽。 This is not the most efficient way to handle this edge case; 这不是处理这种边缘情况的最有效方法; in a version I wrote before I used a dictionary to track active iterables and simply deleted from that to keep indices (keys) stable.
在我之前写的一个版本中,我使用字典来跟踪活动的迭代,并简单地从中删除以保持索引(键)稳定。
Note that you can replace your t()
function with the built-in iter()
function . 请注意,您可以使用内置的
iter()
函数替换t()
iter()
函数 。
Demo: 演示:
>>> 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]
The standard library does it more efficiently still with the heapq.merge()
function ; 标准库仍然使用
heapq.merge()
函数更有效地完成它; it uses a heap to keep the iterables sorted by lowest value in a very efficient manner; 它使用堆来以非常有效的方式保持迭代按最低值排序;
min()
needs to loop through all K iterables, while using a heap only takes log-K steps to keep the heap invariant intact. min()
需要循环遍历所有K个iterables,而使用堆只需要log-K步骤来保持堆不变的完整性。
>>> import heapq
>>> list(heapq.merge(l1, l2, l3))
[0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 10]
You can study the source code , which has been highly tuned for maximum performance. 您可以研究源代码 ,该代码已经过高度调整以获得最佳性能。
I wrote this simple code using the idea of heapq.merge
from Martijn Pieters 我使用Martijn Pieters的
heapq.merge
的想法编写了这个简单的代码
import heapq
def g1():
for i in range(0, 30, 5):
yield i
def g2():
for i in range(15, 25, 2):
yield i
def g3():
for i in range(5, 30, 3):
yield i
result_gen = heapq.merge(
g1(),
g2(),
g3(),
)
## convert it to list
print list(result_gen)
## or simply iterate over it
for x in result_gen:
print x
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.