将Python列表分成n个块

59

我知道这个问题已经被讨论过很多次,但我的要求是不同的。

我有一个列表,如: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]]

正如您所看到的,我没有得到6个块(由原始列表元素组成的六个子列表)。我该如何将一个列表分成恰好 n 个块,这些块可以是偶数或奇数呢?


更通用,功能相同: [ np.array(x)[i:i + chunk_size,...] for i in range(0, len(x), chunk_size) ] - Nir
22个回答

2

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

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

1
可能需要使用 len(x) // 6 来保证在 Python 3 中的兼容性。 - mgilson
x6 的倍数时,这会返回错误的结果,因为在这种情况下,列表的数量是正确的,而不需要重新分配最后一个元素。 - Bakuriu
@Bakuriu:在第一种情况下,可以检查返回的列表数量是否符合预期,如果不符合,则应用转换。 - Sukrit Kalra
如果列表长度为5,而您想将其分成3个块,该怎么办? - coderboi

2
假设您想将其分成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):])

这种方法只是通过列表长度除以块数,如果长度不是块数的倍数,则将额外的元素添加到最后一个列表中。


1

我会简单地这样做(假设你想要n个块)

import numpy as np

# convert x to numpy.ndarray
x = np.array(x)
l = np.array_split(x, n)

它有效,并且只有两行。

示例:

# your list
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]
# amount of chunks you want
n = 6
x = np.array(x)
l = np.array_split(x, n)
print(l)

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

如果你想要一个列表的列表:

l = [list(elem) for elem in l]
print(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]]

1
这是一个长期存在的问题,有很多答案,考虑添加一个解释,说明为什么这是最佳答案,因此应该标记为预期答案。 - User1010
谢谢反馈,我刚刚做了(并添加了一个更正)。 - YannTC

1
这个解决方案基于Python 3文档中的zip "grouper"模式。小的改动是,如果N不能整除列表长度,则所有额外的项目都放入第一个块中。
import itertools

def segment_list(l, N):
    chunk_size, remainder = divmod(len(l), N)
    first, rest = l[:chunk_size + remainder], l[chunk_size + remainder:]
    return itertools.chain([first], zip(*[iter(rest)] * chunk_size))

使用示例:

>>> my_list = list(range(10))
>>> segment_list(my_list, 2)
[[0, 1, 2, 3, 4], (5, 6, 7, 8, 9)]
>>> segment_list(my_list, 3)
[[0, 1, 2, 3], (4, 5, 6), (7, 8, 9)]
>>>

这种解决方案的优点是保留了原始列表的顺序,并以函数式风格编写,只有在调用时才惰性地评估列表一次。
请注意,由于它返回一个迭代器,结果只能被消费一次。如果您想要非惰性列表的便利性,可以将结果包装在list中:
>>> x = list(segment_list(my_list, 2))
>>> x
[[0, 1, 2, 3, 4], (5, 6, 7, 8, 9)]
>>> x
[[0, 1, 2, 3, 4], (5, 6, 7, 8, 9)]
>>>

1
在某些情况下,您的列表可能包含不同类型的元素或可迭代对象,这些对象存储不同类型的值(例如,有些元素是整数,而有些元素是字符串)。如果您使用 numpy 包中的 array_split 函数对其进行拆分,您将获得具有相同类型元素的块:
import numpy as np

data1 = [(1, 2), ('a', 'b'), (3, 4), (5, 6), ('c', 'd'), ('e', 'f')]
chunks = np.array_split(data1, 3)
print(chunks)
# [array([['1', '2'],
#        ['a', 'b']], dtype='<U11'), array([['3', '4'],
#        ['5', '6']], dtype='<U11'), array([['c', 'd'],
#        ['e', 'f']], dtype='<U11')]

data2 = [1, 2, 'a', 'b', 3, 4, 5, 6, 'c', 'd', 'e', 'f']
chunks = np.array_split(data2, 3)
print(chunks)
# [array(['1', '2', 'a', 'b'], dtype='<U11'), array(['3', '4', '5', '6'], dtype='<U11'),
#  array(['c', 'd', 'e', 'f'], dtype='<U11')]

如果您想在列表分割后将元素的初始类型以块的形式呈现,您可以修改 numpy 包中的 array_split 函数的 源代码,或使用 这个实现。请注意保留 HTML 标签。
from itertools import accumulate

def list_split(input_list, num_of_chunks):
    n_total = len(input_list)
    n_each_chunk, extras = divmod(n_total, num_of_chunks)
    chunk_sizes = ([0] + extras * [n_each_chunk + 1] + (num_of_chunks - extras) * [n_each_chunk])
    div_points = list(accumulate(chunk_sizes))
    sub_lists = []
    for i in range(num_of_chunks):
        start = div_points[i]
        end = div_points[i + 1]
        sub_lists.append(input_list[start:end])
    return (sub_list for sub_list in sub_lists)

result = list(list_split(data1, 3))
print(result)
# [[(1, 2), ('a', 'b')], [(3, 4), (5, 6)], [('c', 'd'), ('e', 'f')]]

result = list(list_split(data2, 3))
print(result)
# [[1, 2, 'a', 'b'], [3, 4, 5, 6], ['c', 'd', 'e', 'f']]

0

这个函数接受生成器,而不会一次性消耗它。如果我们知道生成器的大小,那么 bin 大小可以通过 max(1, size // n_chunks) 计算得出。

from time import sleep

def chunks(items, binsize):
    lst = []
    for item in items:
        lst.append(item)
        if len(lst) == binsize:
            yield lst
            lst = []
    if len(lst) > 0:
        yield lst


def g():
    for item in [1, 2, 3, 4, 5, 6, 7]:
        print("accessed:", item)
        sleep(1)
        yield item


for a in chunks(g(), 3):
    print("chunk:", list(a), "\n")

0
简单的硬编码解决方案,这里我将把一个列表分成四分之一。
k, m = divmod(len(yourInputList), 4)
partitionedList = list(yourInputList[i*k+min(i, m):(i+1)*k+min(i+1, m)] for i in range(4))

print(partitionedList[0])
print(partitionedList[1])
print(partitionedList[2])
print(partitionedList[3])

这里使用了两次数字4,你可以在这个硬编码的解决方案中替换成你自己的数字,也可以用你自己的列表替换yourInputList

0
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]]

0

试试这个:

ls = [1, 2, 3, 4, 5, 6 ,7 ,8 ,9]

size = 3

splited = [ls[x:x+splitedSize] for x in range(0, len(ls), size)]

print(splited)

0

此函数将返回一个列表的列表,其中每个子列表中包含最大数量的值(块)。

def chuncker(list_to_split, chunk_size):
    list_of_chunks =[]
    start_chunk = 0
    end_chunk = start_chunk+chunk_size
    while end_chunk <= len(list_to_split)+chunk_size:
        chunk_ls = list_to_split[start_chunk: end_chunk]
        list_of_chunks.append(chunk_ls)
        start_chunk = start_chunk +chunk_size
        end_chunk = end_chunk+chunk_size    
    return list_of_chunks

例子:

ls = list(range(20))

chuncker(list_to_split = ls, chunk_size = 6)

输出:

[[0, 1, 2, 3, 4, 5],[6, 7, 8, 9, 10, 11],[12, 13, 14, 15, 16, 17],[18, 19]]


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接