在 Python 中迭代多个起止值
Posted
技术标签:
【中文标题】在 Python 中迭代多个起止值【英文标题】:Iterate Over Multiple Start-Stop Values in Python 【发布时间】:2019-12-13 18:12:07 【问题描述】:假设我有一个数字l
,我想将它分成大致相等的n
块。例如:
l = 11
n = 3
step = 1 + l // n
for start in range(0, l, step):
stop = min(l, start+step)
print(start, stop)
在这种情况下,第一个块 (chunk 0
) 从 0 变为 4(5 个元素),下一个块 (chunk 1
) 从 4 变为 8(5 个元素),最后一个块 ( chunk 2
) 稍微小一些,从 8 到 11(4 个元素)。当然,l
和 n
的值可能会有所不同,但两个值始终为正整数,n
始终小于 l
。
我需要做的是生成一个列表,该列表将以循环方式遍历每个块,并将一些块信息附加到列表中。该列表应包含块编号的元组(即0
、1
或2
)和该块中的下一个可用起始值(直到该块在stop
值的控制下耗尽) .因此,输出列表将是:
[(0,0), (1,4), (2,8), (0,1), (1,5), (2,9), (0,2), (1,6), (2,10), (0,3), (1,7)]
请注意,最后一个块比前两个块有一个最后一个元素。无论解决方案是什么,它都需要适用于任何l
和n
(只要这两个值都是正整数并且n
总是小于l
)。为简单起见,您可以假设 l
将小于 100,000,000。
生成此列表的最佳方法是什么?
【问题讨论】:
最后一个分组不应该存在:您已经涵盖了第一组中的 4-8 个分块。 哦,你是对的!列表中应该只有 11 个元素。现已更新 【参考方案1】:对问题的两个级别使用两个循环。外部循环通过range(step)
中的所有数字运行起点。从那里,使用该值作为您已经编写的内部循环的起点。请注意,您必须调整输出:当您请求的输出具有 (chunk#, start) 值时,您正在打印 (start, stop) 值。
你能从那里拿走吗?
【讨论】:
我想我必须添加一些停止条件才能打破两个 for 循环?我认为必须有某种方法可以通过 itertools 完成此操作 您可以通过简单的for
循环获得停止条件。一旦你对这些循环进行了编码(enumerate
会给你块#),将它们折叠成一个列表理解。还可以查找“分块列表”以检查您的代数;你可以窃取他们的一些算术。【参考方案2】:
一种可能的解决方案,使用生成器:
from itertools import islice, zip_longest, cycle
def chunk(it, size):
it = iter(it)
return iter(lambda: tuple(islice(it, size)), ())
def generate(l, n):
c, step = cycle(range(n)), l // n + (l % n != 0)
yield from ((next(c), v) for vals in zip_longest(*chunk(range(l), step)) for v in vals if v is not None)
l = 11
n = 3
out = [*generate(l, n)]
print(out)
打印:
[(0, 0), (1, 4), (2, 8), (0, 1), (1, 5), (2, 9), (0, 2), (1, 6), (2, 10), (0, 3), (1, 7)]
为:
l = 9
n = 3
输出是:
[(0, 0), (1, 3), (2, 6), (0, 1), (1, 4), (2, 7), (0, 2), (1, 5), (2, 8)]
【讨论】:
对不起,我在输出上犯了一个错误。请在 OP 中查看正确(更新)的输出 不,l=9
时应该只有 9 个元素。你的答案有 10 个元素
我会修正step
的计算。不仅会提供更好的结果,而且还允许更简单的代码。
@StefanPochmann 我用itertools
完全重写了它,现在它生成了均匀间隔的块。
@slaw 用 itertools 修改了我的答案,现在应该会产生更好的结果。以上是关于在 Python 中迭代多个起止值的主要内容,如果未能解决你的问题,请参考以下文章