将列表拆分为n组的替代方法

时间:2009-10-26 13:46:13

标签: python

假设我有一个任意长度的列表,L:

L = list(range(1000))

将该列表拆分为n组的最佳方法是什么?这是我能够提出的最好的结构,由于某种原因,它不觉得这是完成任务的最佳方式:

n = 25
for i in range(0, len(L), n):
    chunk = L[i:i+25]

是否有内置功能可以解决这个问题?

编辑:早期的答案正在将我的for循环重新编入listcomp,这不是主意;你基本上以不同的形式给我我的确切答案。我看到是否有其他方法可以实现这一点,就像列表上的假设.split或其他东西一样。我也在昨晚写的一些代码中使用它作为生成器:

def split_list(L, n):
    assert type(L) is list, "L is not a list"
    for i in range(0, len(L), n):
        yield L[i:i+n]

6 个答案:

答案 0 :(得分:110)

你走了:

list_of_groups = zip(*(iter(the_list),) * group_size)

示例:

print zip(*(iter(range(10)),) * 3)
[(0, 1, 2), (3, 4, 5), (6, 7, 8)]

如果元素的数量不能被N整除,但你仍想要包含它们,你可以使用izip_longest但它只能在python 2.6之后使用

izip_longest(*(iter(range(10)),) * 3)

结果是生成器,因此如果要打印它,则需要将其转换为列表。

最后,如果您没有python 2.6并且使用旧版本但仍希望获得相同的结果,则可以使用map:

print map(None, *(iter(range(10)),) * 3)
[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, None, None)]

我想在目前为止提供的不同方法之间加一些速度比较:

python -m timeit -s 'from itertools import izip_longest; L = range(1000)' 'list(izip_longest(*(iter(L),) * 3))'
10000 loops, best of 3: 47.1 usec per loop

python -m timeit -s 'L = range(1000)' 'zip(*(iter(L),) * 3)'
10000 loops, best of 3: 50.1 usec per loop

python -m timeit -s 'L = range(1000)' 'map(None, *(iter(L),) * 3)'
10000 loops, best of 3: 50.7 usec per loop

python -m timeit -s 'L = range(1000)' '[L[i:i+3] for i in range(0, len(L), 3)]'
10000 loops, best of 3: 157 usec per loop

python -m timeit -s 'import itertools; L = range(1000)' '[list(group) for key, group in itertools.groupby(L, lambda k: k//3)]'
1000 loops, best of 3: 1.41 msec per loop

列表理解和按方法分组显然比zip,izip_longest和map

答案 1 :(得分:42)

怎么样:

>>> n = 2
>>> l = [1,2,3,4,5,6,7,8,9]
>>> [ l[i:i+n] for i in range(0, len(l), n) ]
[[1, 2], [3, 4], [5, 6], [7, 8], [9]]

答案 2 :(得分:38)

A Python recipe(在Python 2.6中,使用itertools.izip_longest):

def grouper(n, iterable, fillvalue=None):
    "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    return itertools.zip_longest(*args, fillvalue=fillvalue)

使用示例:

>>> list(grouper(3, range(9)))
[(0, 1, 2), (3, 4, 5), (6, 7, 8)]
>>> list(grouper(3, range(10)))
[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, None, None)]

如果您希望最后一组比其他组短,而不是使用fillvalue填充,那么您可以例如像这样更改代码:

>>> def mygrouper(n, iterable):
...     args = [iter(iterable)] * n
...     return ([e for e in t if e != None] for t in itertools.zip_longest(*args))
... 
>>> list(mygrouper(3, range(9)))
[[0, 1, 2], [3, 4, 5], [6, 7, 8]]
>>> list(mygrouper(3, range(10)))
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]

答案 3 :(得分:13)

Itertools.groupby是一个很好的工具,这里只是通过使用整数除法来分割整数列表:

>>> for key, group in itertools.groupby(range(10), lambda k: k//3):
...  print key, list(group)
... 
0 [0, 1, 2]
1 [3, 4, 5]
2 [6, 7, 8]
3 [9]

(列表必须从0开始才能以完整的组开头。)

答案 4 :(得分:8)

n = 25    
list_of_lists = [L[i:i+n] for i in range(0, len(L), n)]

它为您提供了列表[[0..24], [25..49], ..]

如果len(L) % n不为0,则最后一个元素(list_of_lists[-1])长度为len(L)%n。

答案 5 :(得分:0)

这是递归版本。这是低效的,因为Python有递归限制,但是这个版本说明了每个任务都可以通过递归来解决。

def split_to_groups(l, n):
    assert (len(l) / n) < 998, "Can't split to {} groups".format(len(l) / n)
    if l == []:
        return []
    else:
        f = [l[:n]]
        f.extend(split_to_groups(l[n:], n))
        return f