Как разбить список на равные части?
Как разбить список произвольной длины на равные по размеру части?
См. также:
- Как перебирать список частями
- Разбить строку каждые n символов? (для разбиения строк на части)
Как разделить список на равные части в Python
Для разделения списка на равные части в Python можно использовать несколько методов, включая срезы списков, itertools.batched() (Python 3.12+), numpy.array_split() или функции-генераторы. Наиболее прямой подход использует срезы списков с методом range() для перебора списка и создания фрагментов указанного размера.
Содержание
- Базовый метод срезов списков
- Использование itertools.batched() (Python 3.12+)
- Подход с NumPy
- Функции-генераторы
- Метод с использованием списковых включений
- Сравнение производительности
- Обработка крайних случаев
- Заключение
Базовый метод срезов списков
Наиболее распространенный подход использует срезы списков с методом range() для создания фрагментов равного размера. Этот метод прост, читаем и работает во всех версиях Python.
def split_list_simple(my_list, chunk_size):
"""Разделить список на фрагменты указанного размера"""
for i in range(0, len(my_list), chunk_size):
yield my_list[i:i + chunk_size]
# Пример использования
my_list = [1, 2, 3, 4, 5, 6, 7, 8, 9]
chunk_size = 3
chunks = list(split_list_simple(my_list, chunk_size))
print(chunks) # [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
Эта функция перебирает исходный список и на каждой итерации создает новый фрагмент с помощью среза списка от текущего индекса i до i + chunk_size источник.
Как демонстрирует Python Engineer, этот подход создает пакеты данных из итерируемого объекта в списки равной длины n.
Использование itertools.batched() (Python 3.12+)
Для Python 3.12 и более поздних версий функция itertools.batched() предоставляет наиболее элегантное и эффективное решение:
from itertools import batched
my_list = [1, 2, 3, 4, 5, 6, 7, 8, 9]
chunk_size = 3
chunks = list(batched(my_list, chunk_size))
print(chunks) # [(1, 2, 3), (4, 5, 6), (7, 8, 9)]
Как объясняет Real Python, itertools.batched() должна быть вашим предпочтительным инструментом для разделения списка Python на фрагменты фиксированного размера. Она включена в стандартную библиотеку начиная с Python 3.12, что делает ее хорошо протестированной, задокументированной, переносимой и эффективной благодаря нативной реализации на C.
Функция работает как с конечными, так и с бесконечными итерируемыми объектами, лениво оценивая их элементы, и делает ваш код более читаемым и лаконичным.
Подход с NumPy
При работе с приложениями в области науки о данных функция array_split() NumPy предоставляет альтернативу, которая автоматически обрабатывает фрагменты неравного размера:
import numpy as np
my_list = [1, 2, 3, 4, 5, 6, 7, 8]
chunk_size = 3
# Вычисляем необходимое количество фрагментов
num_chunks = len(my_list) // chunk_size + (len(my_list) % chunk_size != 0)
res = np.array_split(my_list, num_chunks)
# Преобразуем numpy-массивы обратно в списки Python
chunks = [list(arr) for arr in res]
print(chunks) # [[1, 2, 3], [4, 5, 6], [7, 8]]
Этот метод особенно полезен, когда размер списка не идеально делится на n источник.
Как отмечает Spark By Examples, numpy.array_split() - еще один простой и эффективный способ разделить список на фрагменты равного размера. Он разделяет массив (или список) на несколько подмассивов равного или почти равного размера.
Функции-генераторы
Функции-генераторы предоставляют способ эффективного использования памяти для обработки больших списков, возвращая фрагменты по одному за раз:
from itertools import islice
def chunked_list(lst, chunk_size):
"""Функция-генератор для возврата фрагментов указанного размера"""
it = iter(lst)
while True:
chunk = list(islice(it, chunk_size))
if not chunk:
break
yield chunk
# Пример использования
my_list = [1, 2, 3, 4, 5, 6, 7, 8, 9]
chunk_size = 3
for chunk in chunked_list(my_list, chunk_size):
print(chunk)
Этот подход использует itertools.islice для эффективного создания фрагментов без загрузки всего списка в память одновременно источник.
Метод с использованием списковых включений
Для тех, кто предпочитает более компактный подход, можно использовать списковое включение:
def chunkify(lst, chunk_size):
"""Разделить список на фрагменты с использованием спискового включения"""
return [lst[i:i+chunk_size] for i in range(0, len(lst), chunk_size)]
# Пример использования
my_list = [1, 2, 3, 4, 5, 6, 7, 8, 9]
chunk_size = 3
chunks = chunkify(my_list, chunk_size)
print(chunks) # [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
Этот однострочный подход лаконичен и эффективен для большинства случаев использования источник.
Сравнение производительности
Различные методы имеют разные характеристики производительности:
| Метод | Использование памяти | Скорость | Читаемость | Версия Python |
|---|---|---|---|---|
itertools.batched() |
Низкое | Быстрая | Отличная | 3.12+ |
| Списковое включение | Среднее | Быстрая | Хорошая | Все |
| Функция-генератор | Низкое | Средняя | Хорошая | Все |
| NumPy array_split | Среднее | Быстрая | Хорошая | С NumPy |
Как подчеркивает Real Python, производительность варьируется в зависимости от размера вашего списка и необходимости ленивой оценки.
Обработка крайних случаев
При разделении списков учитывайте эти крайние случаи:
- Пустой список - должен возвращать пустой список
- Размер фрагмента больше списка - должен возвращать исходный список как единый фрагмент
- Размер фрагмента равен нулю - должен вызывать исключение
- Отрицательный размер фрагмента - должен вызывать исключение
Вот надежная реализация:
def safe_split_list(my_list, chunk_size):
"""Безопасное разделение списка с обработкой ошибок"""
if chunk_size <= 0:
raise ValueError("Размер фрагмента должен быть положительным")
if not my_list:
return []
return list(split_list_simple(my_list, chunk_size))
Для списков, которые не делятся нацело, методы выше создадут последний фрагмент с меньшим количеством элементов. Если вам нужны фрагменты точно равного размера с дополнением, вам потребуется дополнительная логика для обработки этого случая.
Заключение
Разделение списка на равные части в Python можно выполнить несколькими способами:
- Для Python 3.12+: Используйте
itertools.batched()для наиболее элегантного и эффективного решения - Для всех версий Python: Используйте срезы списков с range() для простоты и читаемости
- Для приложений в области науки о данных: Рассмотрите NumPy
array_split()для обработки больших наборов данных - Для эффективного использования памяти: Используйте функции-генераторы для обработки очень больших списков
Выберите метод, который лучше всего соответствует вашей версии Python, требованиям к производительности и стилю программирования. Подход с использованием срезов списков остается наиболее универсальным и читаемым решением для большинства случаев использования.