【问题标题】:How to create generator to merge values from iterables in Python?如何创建生成器以合并 Python 中可迭代的值?
【发布时间】:2016-11-17 14:08:05
【问题描述】:

我想创建生成器,它可以以无穷无尽的方式即时(连续地)合并来自可迭代对象的值。

主要思想是,当您询问时,该生成器每次都会将值生成到输出中。因此,主要功能是无限循环,您可以在其中一个一个地向生成器询问值并将它们打印到输出中。

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

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

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) 是不错的选择,但不知道如何使用)

【问题讨论】:

  • 您可以阅读 itertools.chain 上的文档...

标签: python


【解决方案1】:
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])) 

【讨论】:

  • 我不想保存在内存中,因为我认为 itertools.chain 是一种选择!我也必须无限循环运行它。
  • 在这种情况下,cycle(sorted(chain(*iterables))) 之类的东西可能就是您所需要的。 cyclechain 都来自 itertools。如果你想循环我的,cycle(sort_merge(*iterables)) 也应该足够了。
  • 请您使用您解释的上一个解决方案更新您的代码。
  • 这个循环仅用于固定列表,换句话说,我想创建生成器,它可以以无穷无尽的方式即时(连续地)合并来自可迭代对象的值。虽然值来自迭代器,但生成器会一一返回值以将它们打印到输出中。
  • 您希望迭代的内容会发生变化吗?可能像def g(*iterables): while True: yield from sort_merge(*iterables) 这样的东西可以满足您的需求。
【解决方案2】:

我认为这是 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]))))

来自文档:

创建一个迭代器,从第一个可迭代对象中返回元素,直到 它被耗尽,然后继续下一个迭代,直到所有 可迭代对象已用尽。用于将连续序列视为 单序列

【讨论】:

  • 注意他的输出顺序。我认为这就是问题的全部意义所在。
  • 谢谢大家,但正如我所提到的“我如何在无尽的外观中(连续地)合并来自可迭代对象的值。” ?
  • @BigData 你能解释一下吗?
  • @wolendranh 我在我的问题帖子中解释了我想要什么,再次阅读我的 cmets。
【解决方案3】:

如果我理解正确的话,我相信你所追求的是 itertools.chain Python 3, Python 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)

如果你想用它进行排序,那么我有这个解决方案,但是我不能保证它的效率,我没有计时(因为我没有任何东西可以比较它)但我觉得多重 @ 987654327@ 调用可能不适合非常大的可迭代对象。

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 是一个无限生成器,它在到达终点后循环回到起点。

【讨论】:

  • list(merge(*iterables)) 如果我们的可迭代对象很大,会占用大量内存!
猜你喜欢
  • 2010-12-21
  • 2011-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-10
相关资源
最近更新 更多