Питон "Каждый другой элемент" Идиома

Мне кажется, что я трачу много времени на написание кода на Python, но недостаточно времени на создание Pythonic-кода. Недавно я столкнулся с забавной проблемой, которая, как я думал, может иметь легкое идиоматическое решение. Перефразируя оригинал, мне нужно было собрать каждую последовательную пару в списке. Например, учитывая список [1,2,3,4,5,6], я хотел вычислить [(1,2),(3,4),(5,6)].

В то время я придумал быстрое решение, похожее на переведенную Java. Повторяя вопрос, лучшее, что я мог сделать, это

l = [1,2,3,4,5,6]
[(l[2*x],l[2*x+1]) for x in range(len(l)/2)]

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

Есть ли более идиоматический подход, который мне не хватает, или это лучшее, что я собираюсь получить?

Ответ 1

Это будет делать это более аккуратно:

>>> data = [1,2,3,4,5,6]
>>> zip(data[0::2], data[1::2])
[(1, 2), (3, 4), (5, 6)]

(но это, возможно, менее читаемо, если вы не знакомы с функцией "шага" диапазонов).

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

Ответ 2

Часто цитируется:

zip(*[iter(l)] * 2)

Ответ 3

Я обычно копирую рецепт grouper из itertools в свой код для этого.

def grouper(n, iterable, fillvalue=None):
    "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    return izip_longest(fillvalue=fillvalue, *args)

Ответ 4

Как использовать функцию шага range():

[(l[n],l[n+1]) for n in range(0,len(l),2)]

Ответ 5

попробуйте это

def pairs(l, n):
    return zip(*[l[i::n] for i in range(n)])

Итак,

pairs([1, 2, 3, 4], 2) дает

[(1, 2), (3, 4)]

Ответ 6

Правильная вещь - это, вероятно, не вычисление списков, а запись функции iterator- > iterator. Это более общий - он работает на каждом истребимом, и если вы хотите "заморозить" его в списке, вы можете использовать функцию "list()".

def groupElements(iterable, n):
    # For your case, you can hardcode n=2, but I wanted the general case here.
    # Also, you do not specify what to do if the 
    # length of the list is not divisible by 2
    # I chose here to drop such elements
    source = iter(iterable)
    while True:
        l = []
        for i in range(n):
            l.append(source.next())
        yield tuple(l)

Я удивлен, что модуль itertools еще не имеет функции для этого - возможно, будущей версии. До тех пор не стесняйтесь использовать версию выше:)

Ответ 7

toolz - это хорошо построенная библиотека с множеством функциональных программных тонкостей, забытых в itertools. partition разрешает это (с возможностью вставить последнюю запись для списков нечетной длины)

>>> list(toolz.partition(2, [1,2,3,4,5,6]))
[(1, 2), (3, 4), (5, 6)]

Ответ 8

Если вы не хотите терять элементы, если их число в списке даже не пытается это сделать:

>>> l = [1, 2, 3, 4, 5]
>>> [(l[i],  l[i+1] if i+1 < len(l) else None)  for i in range(0, len(l), 2)]
[(1, 2), (3, 4), (5, None)]