Python разбивает список на n кусков

Я знаю, что этот вопрос был рассмотрен много раз, но мое требование другое.

У меня есть список вроде: 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 куски, которые могут быть четными или неравномерными

Ответ 1

Использовать numpy

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

или

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

Вы также можете использовать numpy.split, но этот код генерирует ошибку, если длина не является точно делимой.

Ответ 2

Если порядок не имеет значения:

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

Ответ 3

Попробуйте следующее:

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

Он возвращает итератор вместо списка для эффективности (я предполагаю, что вы хотите перебрать куски), но вы можете заменить это на понимание списка, если хотите. Когда количество элементов не делится на количество кусков, последний кусок меньше остальных.

EDIT: Исправлен второй пример, показывающий, что он не обрабатывает один крайный фрейм

Ответ 4

more_itertools.divide - это один из способов решения этой проблемы:

import more_itertools as mit


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

Выход

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

Как показано, если итерабельность не равномерно делится, остальные элементы распределяются от первого до последнего фрагмента.

Подробнее о библиотеке more_itertools здесь.

Ответ 5

Решения ниже имеют много преимуществ:

  • Использует генератор для получения результата.
  • Нет импорта.
  • Списки сбалансированы (вы никогда не получите 4 списка размером 4 и один список размера 1, если разделите список длиной 17 на 5).
def chunks(l, n):
    """Yield n number of striped chunks from l."""
    for i in range(0, n):
        yield l[i::n]

Приведенный выше код выдает следующие выходные данные для l = range(16) и n = 6:

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

Если вам нужно, чтобы чанки были последовательными, а не полосатыми, используйте это:

def chunks(l, n):
    """Yield n number of sequential chunks from l."""
    d, r = divmod(len(l), n)
    for i in range(n):
        si = (d+1)*(i if i < r else r) + d*(0 if i < r else i - r)
        yield l[si:si+(d+1 if i < r else d)]

Что для l = range(16) и n = 6 дает:

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

Посмотрите эту ссылку на fooobar.com/questions/13/... для получения дополнительной информации о преимуществах генераторов.

Ответ 6

Предполагая, что вы хотите разделить на 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):])

Этот метод просто делит длину списка на количество кусков, а в случае, если длина не кратная номеру, добавляет дополнительные элементы в последний список.

Ответ 7

Один из способов - сделать последний список неравномерным, а остальное - даже. Это можно сделать следующим образом:

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

Ответ 8

Вы можете просто взять избыток и добавить его в последний список, если я не понимаю вопрос:

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

def group(lst, div):
    lst = [ lst[i:i + len(lst)/div] for i in range(0, len(lst), len(lst)/div) ] #Subdivide list.
    if len(lst) > div: # If it is an uneven list.
        lst[div-1].extend(sum(lst[div:],[])) # Take the last part of the list and append it to the last equal division.
    return lst[:div] #Return the list up to that point.

l = group(x, 6)

pprint.pprint(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]]

Примечание. Вы можете использовать более быстрые методы, чем sum(l, []), чтобы сгладить список, но для краткости я использую это.

Ответ 9

Самый Pythonic способ, который я нашел

n = 6  # Chunk size
list_of_chunks = list(some_list[i:i+n] for i in range(0, len(some_list), n))

Ответ 10

Если вы хотите, чтобы куски были как можно более равномерными:

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

Тестовый пример:

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

Ответ 11

Подсказка:

  • x - строка, которую нужно разделить.
  • k - количество кусков

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

Ответ 12

Вот возьми мои 2 цента..

from math import ceil

size = 3
seq = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]

chunks = [
    seq[i * size:(i * size) + size]
    for i in range(ceil(len(seq) / size))
]

# [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11]]

Ответ 13

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

Ответ 14

Для людей, ищущих ответ в Python 3 (.6) без импорта.
х - список, который нужно разделить.
п - длина кусков.
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]]