使用另一个 python 生成器对生成的数字进行排序
Sort generated numbers using another python 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 中,我使用字典来跟踪活动的可迭代对象,并简单地从中删除以保持索引(键)稳定。
请注意,您可以将 t()
函数替换为内置的 iter()
function。
演示:
>>> 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,它已针对最佳性能进行了高度调整。
我使用来自 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
我正在尝试使用 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 中,我使用字典来跟踪活动的可迭代对象,并简单地从中删除以保持索引(键)稳定。
请注意,您可以将 t()
函数替换为内置的 iter()
function。
演示:
>>> 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,它已针对最佳性能进行了高度调整。
我使用来自 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