list - python如何将一个列表分成相等大小的块?

  显示原文与译文双语对照的内容

我有一个任意长度的列表,我需要将它分割成大小相等的块并对它的进行操作。 有一些明显的方法可以做到这一点,比如保持一个计数器和两个列表,当第二个列表填满时,将它添加到第一个列表中,然后清空第二个列表,但是这可能非常昂贵。

我想知道是否有人对任何长度的列表都有很好的解决方案,比如 使用生成器。

这应该可以工作:


l = range(1, 1000)
print chunks(l, 10) -> [ [ 1..10 ], [ 11..20 ],.. , [ 991..999 ] ]

我在寻找 itertools 中有用的东西,但我找不到任何明显有用的东西。 可能错过了它。

相关问题:是迭代列表的最"Pythonic"方式

时间:

下面是生成所需区块的生成器:


def chunks(l, n):
""" Yield successive n-sized chunks from l.
"""
 for i in xrange(0, len(l), n):
 yield l[i:i+n]



import pprint
pprint.pprint(list(chunks(range(10, 75), 10)))
[[10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
 [20, 21, 22, 23, 24, 25, 26, 27, 28, 29],
 [30, 31, 32, 33, 34, 35, 36, 37, 38, 39],
 [40, 41, 42, 43, 44, 45, 46, 47, 48, 49],
 [50, 51, 52, 53, 54, 55, 56, 57, 58, 59],
 [60, 61, 62, 63, 64, 65, 66, 67, 68, 69],
 [70, 71, 72, 73, 74]]

直接来自( 旧的) python 文档( itertools的菜谱):


from itertools import izip, chain, repeat

def grouper(n, iterable, padvalue=None):
"grouper(3, 'abcdefg', 'x') --> ('a','b','c'), ('d','e','f'), ('g','x','x')"
 return izip(*[chain(iterable, repeat(padvalue, n-1))]*n)

J.F. Sebastian建议的当前版本:


from itertools import izip_longest # for Python 2.x
#from itertools import zip_longest # for Python 3.x
#from six.moves import zip_longest # for both (uses the six compat library)

def grouper(n, iterable, padvalue=None):
"grouper(3, 'abcdefg', 'x') --> ('a','b','c'), ('d','e','f'), ('g','x','x')"
 return izip_longest(*[iter(iterable)]*n, fillvalue=padvalue)

我想贵机器 works—worked—will work—will的时间又有了 worked—was 。

在这些解决方案起作用,因为 [iter(iterable)]*n list, ( 或者在早期版本中等效) 创建 一个迭代器提起。重复 n 然后 izip_longest"每 each"迭代器,因为这是相同的迭代器,它的有效地执行一个round-robin将向前推进每个这样的调用,从而导致每个这样 n zip-roundrobin生成个元组的项。

这是一个可以在任意iterables上工作的生成器:


def split_seq(iterable, size):
 it = iter(iterable)
 item = list(itertools.islice(it, size))
 while item:
 yield item
 item = list(itertools.islice(it, size))

例如:


>>> import pprint
>>> pprint.pprint(list(split_seq(xrange(75), 10)))
[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
 [10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
 [20, 21, 22, 23, 24, 25, 26, 27, 28, 29],
 [30, 31, 32, 33, 34, 35, 36, 37, 38, 39],
 [40, 41, 42, 43, 44, 45, 46, 47, 48, 49],
 [50, 51, 52, 53, 54, 55, 56, 57, 58, 59],
 [60, 61, 62, 63, 64, 65, 66, 67, 68, 69],
 [70, 71, 72, 73, 74]]

我知道这有点旧,但我不知道为什么没有人提到 numpy.array_split:


lst = range(50)
In [26]: np.array_split(b,5)
Out[26]: 
[array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]),
 array([10, 11, 12, 13, 14, 15, 16, 17, 18, 19]),
 array([20, 21, 22, 23, 24, 25, 26, 27, 28, 29]),
 array([30, 31, 32, 33, 34, 35, 36, 37, 38, 39]),
 array([40, 41, 42, 43, 44, 45, 46, 47, 48, 49])]

简单但优雅


l = range(1, 1000)
print [l[x:x+10] for x in xrange(0, len(l), 10)]

或者如果你愿意:


chunks = lambda l, n: [l[x: x+n] for x in xrange(0, len(l), n)]
chunks(l, 10)

如果你的块大小为 3,那么你可以:


zip(*[iterable[i::3] for i in range(3)]) 

源:http://code.activestate.com/recipes/303060-group-a-list-into-sequential-n-tuples/

当我的区块大小是固定的,我可以输入,比如'3',并且不会改变时,我会使用这个。

我喜欢这种 python 版本的doc利用tzot和 J.F.Sebastian 提出了许多,但它的两个缺点:

  • 它不是很明确
  • 我通常不希望在最后一个区块中有一个填充值

我在代码中使用了很多:


from itertools import islice

def chunks(n, iterable):
 iterable = iter(iterable)
 while True:
 yield tuple(islice(iterable, n)) or iterable.next()

更新:惰性块版本:


from itertools import chain, islice

def chunks(n, iterable):
 iterable = iter(iterable)
 while True:
 yield chain([next(iterable)], islice(iterable, n-1))

...