我要找的是
Itertools Recipes的代码部分中描述的函数
batched(iterable, n)
的单线变体,它将把数据批处理成一定长度的元组。
假设源是任意长度的迭代器,例如对 sys.stdin 的迭代,它在我的用例中接收字符串。
最后,我想要一个生成器,它产生一定长度的元组,最后一个元组也可能更短(取决于项目的总数)。
AFAIK,
batched(iterable, n)
将在将于今年晚些时候发布的 Python 3.12 中实现,但我想了解当前版本的 oneliner 解决方案的外观。
这是我到目前为止想出的(例如元组长度为 2):
from itertools import islice, zip_longest
foo=('aaa', 'bbb', 'ccc', 'ddd', 'eee', 'fff', 'ggg',) ## for simulating sys.stdin
# a oneliner that gets close but would fill lacking elements with None, so
# list(slicepairs0) would be [('aaa', 'bbb'), ('ccc', 'ddd'), ('eee', 'fff'), ('ggg', None)]
slicepairs0 = zip_longest(*[iter(foo)]*2)
# a oneliner that gets close but ignores possibly remaining elements, so
# list(slicepairs1) would be [('aaa', 'bbb'), ('ccc', 'ddd'), ('eee', 'fff')]
slicepairs1 = zip(*[iter(foo)]*2)
# a function similar to how batched() is currently implemented
def giveslicepair(foo):
fooi=iter(foo)
while nextslice := tuple(islice(fooi,2)):
yield nextslice
# this iterator does what it should but relies on the generator-funtion giveslicepair(), so
# list(slicepairs2) would be [('aaa', 'bbb'), ('ccc', 'ddd'), ('eee', 'fff'), ('ggg',)]
slicepairs2 = ( item for item in giveslicepair(foo) )
我尝试将 giveslicepair() 的功能体现到最后一行的迭代器表达式中,但无法使其正常工作。感觉我在这里忽略了一些明显的东西,并感谢提示如何以高性能和 pythonic 方式执行此操作。
旁注:在现实世界的应用中,元组的大小通常预计在 50 到 400 左右,而不是只有 2 个。输入的行数可能相差很大,可以是 1 到数十亿之间的任何值。
如果你想要一个班轮,你可以使用
iter()
和 lambda
参数:
from itertools import islice
def one_line_batched(iterable, n):
return iter(lambda it=iter(iterable): tuple(islice(it, n)), tuple())
print(list(one_line_batched('ABCDEFG', 3)))
印花:
[('A', 'B', 'C'), ('D', 'E', 'F'), ('G',)]