Обход списка в Python по два элемента: эффективные способы

Пройдите тест, узнайте какой профессии подходите и получите бесплатную карьерную консультацию
В конце подарим скидку до 55% на обучение
Я предпочитаю
0%
Работать самостоятельно и не зависеть от других
Работать в команде и рассчитывать на помощь коллег
Организовывать и контролировать процесс работы

Быстрый ответ

Если перед нами стоит задача циклического обхода списка с шагом через два элемента, можно воспользоваться следующим кодом, использующим цикл for, функцию range и с шагом 2:

Python
Скопировать код
my_list = [1, 2, 3, 4, 5, 6]
for i in range(0, len(my_list), 2):
    pair = my_list[i:i+2]
    print(tuple(pair))

В результате выполнения данного кода выводом будут кортежи: (1, 2), (3, 4), (5, 6). Данный код работает безошибочно даже в случае списка с нечетной длиной.

Оптимизация производительности в Python 2 благодаря xrange

Если вы продолжаете работать с Python 2, xrange представляет собой отличную альтернативу. Эта функция формирует объект xrange, помогая оптимизировать использование памяти в процессе выполнения цикла:

Python
Скопировать код
for i in xrange(0, len(my_list), 2):
    print(my_list[i:i+2])

Рецепт от мастера: Использование срезов списка

Выражения-срезы позволяют изящно "разделить" данные:

Python
Скопировать код
for pair in my_list[::2]:
    print(pair)

Такой подход позволяет отбирать каждый второй элемент, однако не группирует их в пары.

Формирование пар с помощью функции Zip

Функция zip умеет попарно соединять элементы, даже если они на первый взгляд несовместимы:

Python
Скопировать код
for left_sock, right_sock in zip(my_list[::2], my_list[1::2]):
    print(left_sock, right_sock)

itertools для продвинутого формирования пар

itertools — это эффективный инструмент для работы с парами:

Python
Скопировать код
from itertools import izip
for a, b in izip(*[iter(my_list)]*2):
    print(a, b)

Благодаря функции izip формирование пар возможно даже в кажущихся на первый взгляд неподходящих случаях.

Удобство использования итерируемых объектов

range и xrange создают итерируемые объекты, которые не формируют списки. Это весьма полезно при работе с большими последовательностями данных, когда важно эффективное использование памяти.

Ручная работа с индексами для тонкого контроля

Вам также доступна возможность взять инициативу в свои руки и непосредственно управлять циклом while:

Python
Скопировать код
i = 0
while i < len(my_list) – 1:
    print(my_list[i], my_list[i+1])
    i += 2

Рабочий процесс со списками различной длины

Функция zip_longest из модуля itertools отлично поможет вам формировать пары, когда списки имеют разную длину. Это решение идеально подходит для Python 3.

Визуализация: Вращение шестерёнок

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

Список до начала: [🔧, 🔩, 🛠, 🧰, ⚙️, 🗜️]

1-й проход: [👷‍♂️🔧, 👷‍♂️🔩], [🛠, 🧰], [⚙️, 🗜️]
2-й проход: [🔧, 🔩], [👷‍♂️🛠, 👷‍♂️🧰], [⚙️, 🗜️]
3-й проход: [🔧, 🔩], [🛠, 🧰], [👷‍♂️⚙️, 👷‍♂️🗜️]

👷‍♂️ Рабочий движется по ленте, обрабатывает пару предметов за один проход.

Можно представить, что список 'tools' — это ваш список предметов, а каждый проход цикла — это шаг рабочего по конвейеру.

Тонкая настройка производительности и использования памяти

При выборе метода следует учитывать требования к производительности и эффективности использования памяти. Например, функции range() и xrange() прекрасно подойдут для итераций, не требующих создания списков индексов.

Ручное управление циклами для специфических случаев

Цикл while предоставляет широкие возможности для гибкого управления индексами и позволяет учесть особенности обработки списков с нечетным числом элементов или исключительными ситуациями внутри цикла.

Grouper: Универсальное решение

Функция grouper из модуля itertools предназначена для группировки элементов по заданному размеру:

Python
Скопировать код
from itertools import zip_longest

def grouper(iterable, n, fillvalue=None):
    args = [iter(iterable)] * n
    return zip_longest(*args, fillvalue=fillvalue)

Это универсальный инструмент, облегчающий чтение кода.

Баланс между простотой и эффективностью

Python отдает предпочтение лаконичности и выразительности. Срезы списков прекрасны для простых случаев, но когда детали усложняются, не стоит бояться рассматривать и другие альтернативы.

Полезные материалы

  1. Циклический обход как у профи | Нед Батчелдер – подробное руководство по циклической обработке данных.
  2. itertools — Функции для создания итераторов для эффективного циклического прохождения — Документация Python 3.12.2 – разъяснение использования модуля itertools.
  3. python – Формирования нового списка из каждого N-го элемента исходного списка – Stack Overflow — варианты решений для создания списка из каждого N-го элемента.
  4. Python enumerate(): Упрощение циклов с использованием счётчиков – Real Python – применение функции enumerate() для обозначения этапов в цикле.
  5. Цикл for – Python Wiki – обзор различных приёмов использования цикла for.
  6. Циклы for в Python – обучающий урок по применению цикла for.
  7. Как осуществить циклический обход, используя индексы счетчика, в Python – руководство по реализации циклического прохода со счётчиками.