如何创建生成器来合并Python中迭代的值?

时间:2016-11-17 14:08:05

标签: python

我想创建生成器,它可以在无限的外观中连续地(连续地)合并来自iterables的值。

主要思想是,当您提出要求时,生成器每次都会将值生成到输出中。因此,主要功能是无限循环,您可以逐个询问生成器的值并将其打印到输出中。

虽然值来自迭代器,但生成器会逐个返回值以将它们打印到输出中。

现在,在我的代码中,我将值传递到一个列表中。但是在打印之前没有必要将所有值收集到一个列表中。

def merge(*iterables):
# create a generator
generator = (iter(current) for current in iterables)
# convert generator to a list
iters = list(generator)
# while we have a iterable
while iters:
    #loop through each iterable
    for i in iters:
        try:
            # yields the values one by one 
            yield i.__next__()
        except StopIteration:
            iters.remove(i)

当我这样跑:

>>> callmerge([1,5,9],[2,5],[1,6,10,11])
Result is:
[1, 1, 2, 5, 5, 6, 9, 10, 11]

要明确我有一个例子:

让我们想象一下,我们正在从几个黑盒子里拿出数字(比如宾果)。

我们真的不知道每个盒子里的球数。我们可以从盒子里一个接一个地拿球。

我们知道,来自同一个黑匣子的每一个下一个球的数量都会比以前更大。

所以,我们应该从黑匣子中取出球,并在每一步给出一个数量最小的球给我们的助手。

所以,我的问题是我如何创建生成器,它可以在无休止的外观中合并来自迭代的值(连续)? (由于记忆的原因,我也不会使用列表 - 我知道也许是itertools.chain(* iterables)是不错的选择,但不知道如何使用)

3 个答案:

答案 0 :(得分:0)

我认为这是itertools(Python3Python2)的任务。实施例

from itertools import chain

list(chain.from_iterable(([1,5,9],[2,5],[1,6,10,11])))

[1, 5, 9, 2, 5, 1, 6, 10, 11]

如果您需要它们,您可以在列表

上应用sorted
sorted(list(chain.from_iterable(([1,5,9],[2,5],[1,6,10,11]))))

来自docs:

  

创建一个迭代器,返回第一个iterable中的元素,直到   它耗尽,然后进入下一个迭代,直到所有的   迭代用尽了。用于处理连续序列   单一序列

答案 1 :(得分:0)

def get_vals(*iterables):
    vals = []
    for it in iterables:
        try:
            vals.append(next(it))
        except StopIteration:
            vals.append(None) #Keep indices the same
    return vals

def sort_merge(*iterables):
    iterables = [iter(it) for it in iterables]
    vals = get_vals(*iterables)
    while any(v is not None for v in vals):
        i, m = min(filter(lambda x: x[1] is not None, enumerate(vals)), key=lambda x: x[1])
        yield m
        try:
            vals[i] = next(iterables[i])
        except StopIteration:
            vals[i] = None

您必须实际比较这些值才能对它们进行排序。我不确定这会比仅仅sorted(itertools.chain(...))给你带来任何真正的好处,但这只会在任何给定时间内将len(iterables)个项目保留在内存中。

编辑:要使此(或任何其他迭代器)重复无限期地使用itertools.cycle

itertools.cycle(sort_merge([1,5,9],[2,5],[1,6,10,11])) 

答案 2 :(得分:0)

如果我正确理解了我认为你之后的事情itertools.chain Python 3Python 2允许你将可迭代组合在一起。

def merge(*iterables):
    for i, inner in enumerate(iterables):
        for j, item in enumerate(inner):
            yield i, j, item
# Test Data
x = merge(list(range(3)), list(range(3, 5)))
y = merge(list(range(5, 7)), list(range(8, 10)))

for item in x:
    print(item)

for item in y:
    print(item)

# Output
(0, 0, 0)
(0, 1, 1)
(0, 2, 2)
(1, 0, 3)
(1, 1, 4)

(0, 0, 5)
(0, 1, 6)
(1, 0, 8)
(1, 1, 9)

然后组合两个或更多发电机。

z = itertools.chain(x, y)

for item in z:
    print(item)

# Output
(0, 0, 0)
(0, 1, 1)
(0, 2, 2)
(1, 0, 3)
(1, 1, 4)
(0, 0, 5)
(0, 1, 6)
(1, 0, 8)
(1, 1, 9)

如果你想用它进行分类,那么我就有了这个解决方案,但是我无法保证它的效率,我还没有定时(因为我没有任何东西要比较它)但我觉得多次list次调用可能不适合真正的大型迭代。

def sort(*iterables):
    while True:
        lst = list(merge(*iterables))
        if not lst:
            return
        i, j, v = min(lst, key = lambda tup: tup[2])
        yield iterables[i].pop(j)

>>> list(sort([1,5,9],[2,5],[1,6,10,11]))
[1, 1, 2, 5, 5, 6, 9, 10, 11]

如果你想让它无限期地继续,那么itertools.cycle是一个无限的生成器,在到达结束后循环回到开始。