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

Каждая пара с итулами

На этой неделе я увидел гладкий способ итерации через каждую пару элементов в списке в Python и хотел поделиться им. Tagged с Python, трюками, иртоулами, QuickTip.

Фотография обложки от Дэн Голд на Unsplash Анкет

Быстрое время!

На этой неделе я работал над некоторыми проблемами кодирования над Rosalind в Python. Для одной из проблем мне нужно было пройти через последовательные группы символов в строке и что -то с ними сделать. Например, если строка была «acgtacagtactgacagatca», я хотел работать на следующих подстроках:

"ACGT"
"CGTA"
"GTAC"
"TACA"
...

Если бы я писал в Ruby, это было бы идеальным вариантом использования для каждый_Кон Метод! К сожалению, нет такой удачи с аналогичной функцией, встроенной в Python. Я закончил тем, что пошел с чуть менее красивой:

def each_cons(n, iterable):
    """Returns every n consecutive items in an iterable.
    Example: each_cons(4, range(10)) => [0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]...
    """
    return (iterable[i: i + n] for i in range(len(iterable) - n + 1))

В любое время, когда вы пишете Диапазон (Лен (... , вероятно, есть лучший способ сделать что -то. Если вы знаете, что вы знаете, меньше, чтобы сделать это, пожалуйста, поделитесь им, потому что должен быть лучший способ. Я не могу индексировать вещи вручную, как варвар.

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

Каждая пара с итулами

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

from itertools import tee

def each_pair(iterable):
    """Returns each consecutive pair of items in an iterable"""
    first, second = tee(iterable)
    next(second, None)
    return zip(first, second)

each_pair(range(10))
# => [0, 1], [1, 2], [2, 3], [3, 4], [4, 5]...

Ааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааа ТАК ХОРОШО.

Магия объяснила

Итак, как это работает?

Во -первых, мы используем itertools.tee , который возвращает две копии оригинального итерабильного (причудливое слово для всего, что вы можете перевернуть: строки, списки, генераторы и т. Д.). Также требуется дополнительный аргумент для n Если вы хотите сделать n копии вместо 2.

Теперь у нас есть две идентичные копии оригинального итерабильного. Затем мы называем Следующий На втором, чтобы шагнуть на один элемент вперед. Обратите внимание на второй аргумент в отношении Следующий В Нет Анкет Следующий Функция возвращает (и использует) следующий элемент в итерабильном, и если вы предоставите ему по умолчанию И он не может вернуть другой элемент, потому что это итерабильный пуст, он просто возвращает по умолчанию.

# next only works on Iterator objects
a = iter([1, 2, 3])
next(a, "EMPTY")
# => 1
next(a, "EMPTY")
# => 2
next(a, "EMPTY")
# => 3
next(a, "EMPTY")
# => "EMPTY"
next(a)
# => Error!  StopIteration!

Это всего лишь аккуратный способ сказать «цикл второй иерный один элемент вперед, но если вы уже пустые, не беспокойтесь об этом. Только не бросайте ошибку “. Вы, наверное, также заметили, что мы ничего не делаем с результатом этого призыва Следующий Анкет Мы просто выбрасываем предмет, если он существует.

Последняя часть – это застегнуть два иеры вместе. Zip это сложная функция, которая кажется простой, но часто может быть трудно обернуть голову. Это делает каждый n-й элемент каждого итератора, который передается в один список.

В примере легче увидеть:

a = [1, 2, 3, 4]
b = ["Apple", "Banana", "Pear", "Soup"]
c = [True, False, True, False]

zip(a, b, c)
# => [
#        [1, "Apple", True],
#        [2, "Banana", False],
#        [3, "Pear", True],
#        [4, "Soup", False],
# ]

Хитрость в том, что, если наши списки имеют разные длины, он будет использовать только до самой короткой.

a = [1, 2, 3, 4, 5, 6, 7, 8]
b = [1, 2, 3]
zip(a, b)
# => [[1, 1], [2, 2], [3, 3]]  See how it drops the last 5 elements of 'a'?

итулс Модуль также имеет Zip_longest Функция, которая требует значения по умолчанию, чтобы заполнить, если некоторые из аргументов в ZIP слишком короткие.

a = [1, 2, 3, 4, 5, 6]
b = [1, 2]
itertools.zip_longest(a, b, fillvalue=":)")
# => [
#     [1, 1],
#     [2, 2],
#     [3, ":)"]
#     [4, ":)"]
#     [5, ":)"]
#     [6, ":)"]
# ]

Заворачивать

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

Как я уже говорил, если у вас есть лучший способ сделать каждый_Кон Функция выше, я хочу это увидеть. Обязательно прокомментируйте или Твитнуть в Твиттере на меня Анкет

Первоначально опубликовано Assert_not Magic?

Оригинал: “https://dev.to/rpalo/each-pair-with-itertools-3n4e”