Python 将列表拆分为 n 个块

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24483182/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 04:40:15  来源:igfitidea点击:

Python split list into n chunks

python

提问by user110

I know this question has been covered many times but my requirement is different.

我知道这个问题已被多次提及,但我的要求是不同的。

I have a list like: range(1, 26). I want to divide this list into a fixed number n. Assuming n = 6.

我有这样一个列表:range(1, 26)。我想把这个列表分成一个固定的数字n。假设 n = 6。

>>> x
[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]
>>> l = [ x [i:i + 6] for i in range(0, len(x), 6) ]
>>> l
[[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]]

As you can see I didn't get 6 chunks (six sublists with elements of original list). How do I divide a list in such a way that I get exactly nchunks which may be even or uneven

正如你所看到的,我没有得到 6 个块(六个带有原始列表元素的子列表)。我如何以这样的方式划分列表,以便我得到n可能是均匀或不均匀的块

回答by Sukrit Kalra

One way would be to make the last list uneven and the rest even. This can be done as follows:

一种方法是使最后一个列表不均匀,其余列表均匀。这可以按如下方式完成:

>>> x
[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]
>>> m = len(x) // 6
>>> test = [x[i:i+m] for i in range(0, len(x), m)]
>>> test[-2:] = [test[-2] + test[-1]]
>>> test
[[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]]

回答by sundar nataraj

x=[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]
chunk = len(x)/6

l=[]
i=0
while i<len(x):
    if len(l)<=4:
        l.append(x [i:i + chunk])
    else:
        l.append(x [i:])
        break
    i+=chunk   

print l

#output=[[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]]

回答by user2963623

Assuming you want to divide into n chunks:

假设你想分成n个块:

n = 6
num = float(len(x))/n
l = [ x [i:i + int(num)] for i in range(0, (n-1)*int(num), int(num))]
l.append(x[(n-1)*int(num):])

This method simply divides the length of the list by the number of chunks and, in case the length is not a multiple of the number, adds the extra elements in the last list.

此方法简单地将列表的长度除以块的数量,如果长度不是数字的倍数,则在最后一个列表中添加额外的元素。

回答by user2963623

Try this:

尝试这个:

from __future__ import division

import math

def chunked(iterable, n):
    """ Split iterable into ``n`` iterables of similar size

    Examples::
        >>> l = [1, 2, 3, 4]
        >>> list(chunked(l, 4))
        [[1], [2], [3], [4]]

        >>> l = [1, 2, 3]
        >>> list(chunked(l, 4))
        [[1], [2], [3], []]

        >>> l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
        >>> list(chunked(l, 4))
        [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]

    """
    chunksize = int(math.ceil(len(iterable) / n))
    return (iterable[i * chunksize:i * chunksize + chunksize]
            for i in range(n))

It returns an iterator instead of a list for efficiency (I'm assuming you want to loop over the chunks), but you can replace that with a list comprehension if you want. When the number of items is not divisible by number of chunks, the last chunk is smaller than the others.

它返回一个迭代器而不是一个列表以提高效率(我假设您想遍历块),但如果您愿意,您可以将其替换为列表理解。当项目数不能被块数整除时,最后一个块小于其他块。

EDIT: Fixed second example to show that it doesn't handle one edge case

编辑:修复了第二个示例以表明它不处理一个边缘情况

回答by Jason Mitchell

Use numpy

使用 numpy

>>> import numpy
>>> x = range(25)
>>> l = numpy.array_split(numpy.array(x),6)

or

或者

>>> import numpy
>>> x = numpy.arange(25)
>>> l = numpy.array_split(x,6);

You can also use numpy.split but that one throws in error if the length is not exactly divisible.

您也可以使用 numpy.split 但如果长度不能完全整除,则会出错。

回答by David Barragán Merino

If order doesn't matter:

如果顺序无关紧要:

def chunker_list(seq, size):
    return (seq[i::size] for i in range(size))

print(list(chunker_list([1, 2, 3, 4, 5], 2)))
>>> [[1, 3, 5], [2, 4]]

print(list(chunker_list([1, 2, 3, 4, 5], 3)))
>>> [[1, 4], [2, 5], [3]]

print(list(chunker_list([1, 2, 3, 4, 5], 4)))
>>> [[1, 5], [2], [3], [4]]

print(list(chunker_list([1, 2, 3, 4, 5], 5)))
>>> [[1], [2], [3], [4], [5]]

print(list(chunker_list([1, 2, 3, 4, 5], 6)))
>>> [[1], [2], [3], [4], [5], []]

回答by pylang

more_itertools.divideis one approach to solve this problem:

more_itertools.divide是解决这个问题的一种方法:

import more_itertools as mit


iterable = range(1, 26)
[list(c) for c in mit.divide(6, iterable)]

Output

输出

[[ 1,  2,  3,  4, 5],                       # remaining item
 [ 6,  7,  8,  9],
 [10, 11, 12, 13],
 [14, 15, 16, 17],
 [18, 19, 20, 21],
 [22, 23, 24, 25]]

As shown, if the iterable is not evenly divisible, the remaining items are distributed from the first to the last chunk.

如图所示,如果 iterable 不能被均匀整除,则剩余的项目从第一个块到最后一个块分布。

See more about the more_itertoolslibrary here.

此处查看有关该more_itertools库的更多信息。

回答by marko.ristin

If you want to have the chunks as evenly sized as possible:

如果您想让块的大小尽可能均匀:

def chunk_ranges(items: int, chunks: int) -> List[Tuple[int, int]]:
    """
    Splits the items into chunks defined by begining (inclusive) and end (exclusive) indices.
    If there are fewer items than chunks, each chunk contains an item and there are fewer returned chunk indices
    than the argument `chunks`.

    :param items: number of items in the batch.
    :param chunks: number of chunks
    :return: list of (chunk begin inclusive, chunk end exclusive)
    """
    assert chunks > 0, "Unexpected non-positive chunk count: {}".format(chunks)

    result = []  # type: List[Tuple[int, int]]
    if items <= chunks:
        for i in range(0, items):
            result.append((i, i + 1))
        return result

    chunk_size, extras = divmod(items, chunks)

    start = 0
    for i in range(0, chunks):
        if i < extras:
            end = start + chunk_size + 1
        else:
            end = start + chunk_size

        result.append((start, end))
        start = end

    return result

Test case:

测试用例:

def test_chunk_ranges(self):
    self.assertListEqual(chunk_ranges(items=8, chunks=1),
                         [(0, 8)])

    self.assertListEqual(chunk_ranges(items=8, chunks=2),
                         [(0, 4), (4, 8)])

    self.assertListEqual(chunk_ranges(items=8, chunks=3),
                         [(0, 3), (3, 6), (6, 8)])

    self.assertListEqual(chunk_ranges(items=8, chunks=5),
                         [(0, 2), (2, 4), (4, 6), (6, 7), (7, 8)])

    self.assertListEqual(chunk_ranges(items=8, chunks=6),
                         [(0, 2), (2, 4), (4, 5), (5, 6), (6, 7), (7, 8)])

    self.assertListEqual(chunk_ranges(items=8, chunks=7),
                         [(0, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (7, 8)])

    self.assertListEqual(chunk_ranges(items=8, chunks=9),
                         [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (7, 8)])

回答by Mitendra

Hint:

暗示:

  • x is the string to be split.
  • k is number of chunks

    n = len(x)/k
    
    [x[i:i+n] for i in range(0, len(x), n)]
    
  • x 是要拆分的字符串。
  • k 是块的数量

    n = len(x)/k
    
    [x[i:i+n] for i in range(0, len(x), n)]
    

回答by Brohm

For people looking for an answer in python 3(.6) without imports.
x is the list to be split.
n is the length of chunks.
L is the new list.

对于在没有导入的情况下在 python 3(.6) 中寻找答案的人。
x 是要拆分的列表。
n 是块的长度。
L 是新列表。

n = 6
L = [x[i:i + int(n)] for i in range(0, (n - 1) * int(n), int(n))]

#[[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]]