灵感来自 this earlier stack overflow question我一直在考虑如何在 python 中随机交错迭代,同时保留每个迭代中元素的顺序。例如:
>>> def interleave(*iterables):
... "Return the source iterables randomly interleaved"
... <insert magic here>
>>> interleave(xrange(1, 5), xrange(5, 10), xrange(10, 15))
[1, 5, 10, 11, 2, 6, 3, 12, 4, 13, 7, 14, 8, 9]
原始问题要求随机交错两个列表 a 和 b,可接受的解决方案是:
>>> c = [x.pop(0) for x in random.sample([a]*len(a) + [b]*len(b), len(a)+len(b))]
但是,此解决方案仅适用于两个列表(尽管它可以轻松扩展)并且依赖于 a 和 b 是列表这一事实,因此 pop()
和 len()
可以在它们上调用,这意味着它不能与可迭代对象一起使用。它还具有清空源列表 a 和 b 的不幸副作用。
针对原始问题给出的替代答案会复制源列表以避免修改它们,但这让我觉得效率低下,尤其是在源列表很大的情况下。备选答案也使用 len()
,因此不能仅用于可迭代对象。
我编写了自己的解决方案,适用于任意数量的输入列表并且不会修改它们:
def interleave(*args):
iters = [i for i, b in ((iter(a), a) for a in args) for _ in xrange(len(b))]
random.shuffle(iters)
return map(next, iters)
但此解决方案还依赖于作为列表的源参数,以便可以对它们使用 len()
。
那么,有没有一种有效的方法可以在 python 中随机交错迭代,保留元素的原始顺序,不需要提前知道迭代的长度,也不需要复制迭代?
编辑:请注意,与原始问题一样,我不需要随机化来公平。
最佳答案
这是使用生成器实现的一种方法:
import random
def interleave(*args):
iters = map(iter, args)
while iters:
it = random.choice(iters)
try:
yield next(it)
except StopIteration:
iters.remove(it)
print list(interleave(xrange(1, 5), xrange(5, 10), xrange(10, 15)))
关于python - 随机交错多个迭代,同时在 python 中保留它们的顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10648331/