我有一个任意长度的列表,我需要将它分成相同大小的块并对其进行操作 . 有一些明显的方法可以做到这一点,比如保留一个计数器和两个列表,当第二个列表填满时,将它添加到第一个列表并清空下一轮数据的第二个列表,但这可能非常昂贵 .
我想知道是否有人对任何长度的列表都有一个很好的解决方案,例如使用发电机 .
我在寻找 itertools
中有用的东西,但我不能错过它 .
相关问题:What is the most “pythonic” way to iterate over a list in chunks?
30 回答
此时,我认为我们需要强制性的匿名递归功能 .
批评其他答案:
这些答案中没有一个是大小均匀的块,它们最后都留下了一个小块,所以它们并不是完全 balancer 的 . 如果你使用这些功能来分配工作,你已经内置了一个可能在其他人之前完成的前景,所以当其他人继续努力工作时,它会无所事事 .
例如,当前的最佳答案以:
我最后讨厌那个小矮人!
其他人,如
list(grouper(3, xrange(7)))
和chunk(xrange(7), 3)
都返回:[(0, 1, 2), (3, 4, 5), (6, None, None)]
.None
只是填充,在我看来相当不优雅 . 它们不是均匀地分块迭代 .为什么我们不能更好地划分这些?
我的解决方案
这里's a balanced solution, adapted from a function I' ve用于 生产环境 (在Python 3中注意用
range
替换xrange
):我创建了一个生成器,如果你把它放到一个列表中,它会做同样的事情:
最后,因为我看到所有上述函数都以连续的顺序返回元素(如给出的那样):
输出
测试它们:
打印出来:
请注意,连续生成器以与其他两个相同的长度模式提供块,但是这些项都是有序的,并且它们被均匀地划分为可以划分离散元素的列表 .
码:
结果:
简约而优雅
或者如果您愿意:
这是一个适用于任意迭代的生成器:
例:
我很惊讶没有人想过使用
iter
的two-argument form:演示:
这适用于任何可迭代的并且懒惰地产生输出 . 它返回元组而不是迭代器,但我认为它有一定的优雅 . 它也不垫;如果你想要填充,上面的一个简单的变化就足够了:
演示:
像基于
izip_longest
的解决方案一样,上面的内容总是如此 . 据我所知,没有一行或两行的itertools配方可选择填充功能 . 通过结合上述两种方法,这一方法非常接近:演示:
我相信这是提供可选填充的最短时间段 .
作为Tomasz Gandor observed,如果两个填充块遇到一长串填充值,它们将意外停止 . 这是一个以合理的方式解决该问题的最终变体:
演示:
生成器表达式:
例如 .
嘿,一行版
我知道这有点旧,但我不知道为什么没有人提到
numpy.array_split
:不调用len(),这对大型列表有用:
这是针对迭代的:
以上的功能味道:
要么:
要么:
这是一个产生你想要的块的生成器:
如果您使用的是Python 2,则应使用
xrange()
而不是range()
:您也可以简单地使用列表理解而不是编写函数 . Python 3:
Python 2版本:
如果您知道列表大小:
如果你不(迭代器):
在后一种情况下,如果你可以确定序列总是包含给定大小的整数个块(即没有不完整的最后一个块),它可以以更漂亮的方式重新表述 .
用法:
在这一点上,我认为我们需要 recursive generator ,以防万一......
在python 2中:
在python 3中:
此外,在大规模的外星人入侵的情况下, decorated recursive generator 可能会变得方便:
我很好奇不同方法的表现,这里是:
在Python 3.5.1上测试
Results:
直接来自(旧)Python文档(itertools的配方):
目前的版本,由J.F.Sebastian建议:
我猜Guido的时间机器工作 - 工作 - 将工作 - 将工作 - 再次工作 .
这些解决方案有效,因为
[iter(iterable)]*n
(或早期版本中的等价物)创建了一个迭代器,重复n
次列表 .izip_longest
然后有效地执行"each"迭代器的循环;因为这是相同的迭代器,所以每个这样的调用都会使它前进,从而导致每个这样的zip-roundrobin生成一个n
项的元组 .考虑使用matplotlib.cbook件
例如:
toolz库具有
partition
功能:我喜欢tzot和J.F.Sebastian提出的Python doc版本,但它有两个缺点:
它不是很明确
我通常不希望最后一个块中有填充值
我在我的代码中经常使用这个:
更新:懒人块版本:
还有一个解决方案
您也可以使用get_chunks函数utilspie库:
你可以通过pip安装utilspie:
免责声明:我是utilspie库的创建者 .
我在这个问题的_206360中看到了最棒的Python-ish答案:
你可以为任何n创建n元组 . 如果
a = range(1, 15)
,那么结果将是:如果列表均匀分配,则可以将
zip_longest
替换为zip
,否则三元组(13, 14, None)
将丢失 . 上面使用了Python 3 . 对于Python 2,请使用izip_longest
.例如,如果您的块大小为3,则可以执行以下操作:
来源:http://code.activestate.com/recipes/303060-group-a-list-into-sequential-n-tuples/
当我的块大小是我可以输入的固定数字时,我会使用它,例如'3',永远不会改变 .
如果你想要一些超级简单的事:
另一个更明确的版本 .
既然大家都在谈论迭代器 . boltons有完美的方法,称为iterutils.chunked_iter .
输出:
但是如果你不想对内存怜悯,你可以使用旧方式并使用iterutils.chunked将完整的
list
存储起来 .AA是数组,SS是块大小 . 例如: