Вступление
Разделение строк и списков - обычные действия при программировании на 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()
принимает аргументы: lst
для
списка и 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_
в 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
или иначе.
Разбить список на N четных фрагментов
В предыдущем разделе мы разделили список в зависимости от размера отдельных фрагментов, чтобы в каждом фрагменте было одинаковое количество элементов. Есть другой способ интерпретировать эту проблему. Что мы делаем, когда хотим разбить список не на основе количества элементов в каждом фрагменте, а на основе количества фрагментов, которые мы хотим создать?
Например, вместо того, чтобы разбивать список на части, каждый из которых состоит из 7 элементов, мы хотим разбить список на 7 четных частей. В этом случае мы можем не знать размер каждого фрагмента.
Логика аналогична предыдущим решениям, однако размер блока - это
максимальное значение длины списка, деленное на количество требуемых
блоков. Как и в предыдущих примерах кода, если в блоке есть свободные
места, они будут заполнены значением заполнителя 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
.
Заключение
В этой статье мы рассмотрели некоторые способы, которыми список может быть разделен на части и списки одинакового размера на основе пользовательских методов и с помощью встроенных модулей.
Решения, упомянутые в этом руководстве, не ограничиваются определенными здесь, но есть несколько других творческих способов, с помощью которых вы также можете разделить свой список на равные части.