Рубрики
Без рубрики

Как разбить список на ровные куски в Python

В этой статье мы покажем, как разбить список на куски четного размера в Python – разбить на куски из N элементов и на следующие куски одинакового размера.

Автор оригинала: Sathiya Sarathi Gunasekaran.

Вступление

Разбиение строк и списков – это обычная программная деятельность в Python и других языках. Иногда нам приходится разбивать наши данные особым образом, но чаще – на ровные куски.

Язык не имеет встроенной функции для этого, и в этом уроке мы рассмотрим как разбить список на четные куски в Python .

В большинстве случаев это можно сделать с помощью генераторов:

def chunk_using_generators(lst, n):
    for i in range(0, len(lst), n):
        yield lst[i:i + n]

Хотя есть и другие интересные способы сделать это, каждый со своими плюсами и минусами!

Разбейте список На Четные куски из N Элементов

Список может быть разделен на основе размера определенного фрагмента. Это означает, что мы можем определить размер куска. Если подмножество списка не помещается в размер определенного фрагмента, заполнители должны быть вставлены вместо пустых держателей элементов. В этих случаях мы будем использовать None .

Давайте создадим новый файл с именем chunk_based_on_size.py и добавить следующее содержание:

def chunk_based_on_size(lst, n):
    for x in range(0, len(lst), n):
        each_chunk = lst[x: n+x]

        if len(each_chunk) < n:
            each_chunk = each_chunk + [None for y in range(n-len(each_chunk))]
        yield each_chunk

print(list(chunk_based_on_size([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], 7)))

Приведенная выше функция chunk_based_on_size() принимает аргументы: list для списка и chunk_size для числа, на которое его нужно разделить. Функция выполняет итерацию по списку с приращением размера блока n . Ожидается, что каждый кусок будет иметь размер, заданный в качестве аргумента. Если элементов недостаточно для разделения одного размера, оставшиеся неиспользуемые элементы заполняются символом None .

Запуск этого скрипта возвращает следующий список списков:

$ python3 chunk_based_on_size.py
[[1, 2, 3, 4, 5, 6, 7], [8, 9, 10, 11, 12, 13, None]]

Список был разделен на равные куски по 7 элементов каждый.

Python имеет утилиты для упрощения этого процесса. Мы можем использовать функцию zip_longest из itertools для упрощения предыдущей функции. Давайте создадим новый файл chunk_using_itertools.py и добавьте следующий код:

from itertools import zip_longest

def chunk_using_itertools(lst):
    iter_ = iter(lst)
    return list(zip_longest(iter_, iter_, iter_, iter_, iter_, iter_, iter_))

print(chunk_using_itertools([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]))

Этот код повторяет элементы и возвращает фрагмент желаемой длины – на основе предоставленных вами аргументов. Мы поместили здесь 7 iter_ аргументов. Функция zip_longest() агрегирует и возвращает элементы из каждой итерации. В этом случае он будет агрегировать элементы из списка, который повторяется 7 раз за один раз. Затем создается множество итераторов, содержащих 7 последовательных элементов, которые затем преобразуются в список и возвращаются.

Когда вы выполните этот фрагмент кода, он приведет к:

$ python3 chunk_using_itertools.py
[[1, 2, 3, 4, 5, 6, 7], [8, 9, 10, 11, 12, 13, None]]

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

Лучшим решением было бы использование генераторов. Давайте создадим новый файл, chunk_using_generators.py :

def chunk_using_generators(lst, n):
    for i in range(0, len(lst), n):
        yield lst[i:i + n]

print(list(chunk_using_generators([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], 7)))

Этот генератор дает подсписок, содержащий n элементов. В конце концов, это дало бы подсписок для каждого куска. Запуск этого кода приводит к такому результату:

$ python3 chunk_using_generators.py
[[1, 2, 3, 4, 5, 6, 7], [8, 9, 10, 11, 12, 13]]

Это решение работает лучше всего, если вам не нужно заполнение с помощью None или иным образом.

Разбейте список На Ровные Куски

В предыдущем разделе мы разделили список на основе размера отдельных фрагментов так, чтобы каждый фрагмент имел одинаковое количество элементов. Есть и другой способ интерпретировать эту проблему. Что мы делаем, когда хотим разбить список не по количеству элементов в каждом фрагменте, а по количеству фрагментов, которые мы хотим создать?

Например, вместо того, чтобы разбивать список на куски, где каждый кусок имеет 7 элементов, мы хотим разбить список на 7 четных кусков. В этом случае мы можем не знать размер каждого куска.

Логика аналогична предыдущим решениям, однако размер блока-это предельное значение длины списка, деленное на количество требуемых блоков. Как и в предыдущих примерах кода, если в куске есть свободные места, они будут заполнены значением filler None :

import math

def chunk_based_on_number(lst, chunk_numbers):
    n = math.ceil(len(lst)/chunk_numbers)

    for x in range(0, len(lst), n):
        each_chunk = lst[x: n+x]

        if len(each_chunk) < n:
            each_chunk = each_chunk + [None for y in range(n-len(each_chunk))]
        yield each_chunk

print(list(chunk_based_on_number([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], chunk_numbers=7)))

Мы определяем, сколько списков нам нужно создать и сохранить это значение в n . Затем мы создаем подсписок для двух элементов одновременно, заполняя выходные данные в случае, если размер нашего фрагмента меньше желаемой длины.

Когда мы выполним этот файл мы увидим:

$ python3 chunk_based_on_number.py
[[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12], [13, None]]

Как видно из приведенных выше выходных данных, список был разделен на 7 отдельных списков равных размеров на основе предоставленного аргумента chunk_numbers .

Вывод

В этой статье мы рассмотрели некоторые способы, с помощью которых список можно разбить на куски четного размера и списки на основе пользовательских методов и с помощью встроенных модулей.

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