Способ перебора двух элементов в списке за раз?

Мне интересно, есть ли лучший способ перебирать два элемента в списке за раз. Я много работаю с Maya, и одна из ее команд (listConnections) возвращает список переменных значений. Список будет иметь вид [connectionDestination, connectionSource, connectionDestination, connectionSource]. Чтобы сделать что-нибудь с этим списком, я в идеале хотел бы сделать что-то подобное:

for destination, source in cmds.listConnections():
    print source, destination

Вы можете, конечно, просто перебирать каждый другой элемент в списке, используя [:: 2], а enumerate и source будет index + 1, но тогда вам придется добавить дополнительные проверки для нечетных списков и прочего.

Самое близкое, что я придумал, это:

from itertools import izip
connections = cmds.listConnections()
for destination, source in izip(connections[::2], connections[1::2]):
    print source, destination

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


person Mathieson    schedule 05.07.2012    source источник
comment
взгляните на этот пост, может быть, это поможет заголовок stackoverflow.com/questions/1624883/   -  person Hans Z    schedule 05.07.2012
comment
Кроме того, то, что у вас есть, кажется хорошим способом сделать это. это работает?   -  person Hans Z    schedule 05.07.2012


Ответы (2)


Вы можете использовать следующий метод группировки элементов из итеративного объекта, взятый из документации для zip():

connections = cmds.listConnections()
for destination, source in zip(*[iter(connections)]*2):
    print source, destination

Или для более удобочитаемой версии используйте рецепт группировщика из документации itertools:

def grouper(n, iterable, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    return izip_longest(fillvalue=fillvalue, *args)
person Andrew Clark    schedule 05.07.2012
comment
Ух ты. Мне потребовалось время, чтобы понять, как работает grouper(). Мы строим список args так, чтобы все аргументы были ссылками на один итератор; таким образом, когда itertools.izip_longest() пытается извлечь значение из каждой последовательности, он действительно извлекает следующее значение из того же итератора! Элегантно и эффективно! - person steveha; 05.07.2012

Все, отличный вопрос и ответ. Я хотел бы предоставить другое решение, которое должно дополнить ответ Эндрю Кларка (реквизиты для использования itertools!). Его ответ возвращает каждое значение один раз следующим образом:

iterable = [0, 1, 2, 3, 4, 5, 6,...] n = 2 grouper(n, iterable, fillvalue=None) --> [(0, 1), (2, 3), (3, 4), (5, 6),...]

В приведенном ниже коде каждое значение появится в n подпоследовательностях. Нравится:

def moving_window(n, iterable):
  start, stop = 0, n
  while stop <= len(iterable):
      yield iterable[start:stop]
      start += 1
      stop += 1

--> [(0, 1), (1, 2), (2, 3), (3, 4),...]

Обычное применение этого типа «скользящего окна» или «ядра» - скользящие средние в науке и финансах.

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

person John C. King    schedule 15.07.2015