Python: Как преобразовать «плоскую» последовательность в последовательность кортежей? - PullRequest
0 голосов
/ 09 марта 2011

Мне нужно было составить список из двух кортежей из одномерного списка координат, например [1, 2, 1, 5] нужно стать [(1, 2), (1, 5)]. Как это случилось, я уже нашел самый быстрый, самый общий способ сделать это в Activestate , но код, указанный там, непрозрачен для относительного новичка Python:

def group3(lst, n):
    return itertools.izip(*[itertools.islice(lst, i, None, n) for i in range(n)])

Может кто-нибудь объяснить, что этот код делает на английском языке? Что звездочка делает в этом контексте? Спасибо.

Ответы [ 2 ]

2 голосов
/ 09 марта 2011

Функция itertools.islice может создавать срез из любой итерации. Утверждение:

itertools.islice(lst, 0, None, 2)

В упрощенном выражении означает «вернуть итератор, который при оценке вернет все остальные элементы в lst, начиная с элемента в 0». 0 arg - это начальная точка, а 2 - это значение шага (сколько пропустить, чтобы получить следующее значение)

Было бы лучше использовать список из 6 элементов для иллюстрации, поскольку, глядя на [(1, 2), (1, 5)], может быть неясно, какая функция создает внутренние кортежи (они не создаются до окончательного izip).

>>> lst = [1, 2, 3, 4, 5, 6]
>>> list(itertools.islice(lst, 0, None, 2))
[1, 3, 5]
>>> list(itertools.islice(lst, 0, None, 2))
[2, 4, 6]

Будьте осторожны, используя это с генератором; первый вызов пройдет всю последовательность, опустошив генератор:

>>> def foo():
...     for i in range(6):
...         yield i + 1
>>>
>>> gen = foo()
>>> list(itertools.islice(gen, 0, None, 2)
[1, 3, 5]
>>> list(itertools.islice(gen, 1, None, 2)
[]

Ваша функция должна производить 2 последовательности, шансы и четности. Вот где приходит понимание списка:

>>> [itertools.islice(lst, i, None, 2) for i in range(2)]
[<itertools.islice object at 0x7f958a79eaf8>, <itertools.islice object at 0x7f958a79eaa0>]

Теперь у вас есть 2 объекта островков, готовых к перемежению. Для этого мы могли бы использовать zip, но itertools.izip более эффективно, поскольку возвращает итератор:

>>> list(zip([1, 3, 5], [2, 4, 6]))
[(1, 2), (3, 4), (5, 6)]
>>> tmp = itertools.izip(*[itertools.islice(lst, i, None, 2) for i in range(2)])
>>> tmp
<itertools.izip object at 0x7f958a7b6cf8>
>>> list(tmp)
[(1, 2), (3, 4), (5, 6)]

Надеюсь, это поможет прояснить шаги.

1 голос
/ 09 марта 2011

Вот альтернативная версия для 2-х кортежей (не такая общая, как рецепт активного состояния):

>>> x = [1,2,3,4,5,6,7,8]
>>> [ (x.pop(0), x.pop(0)) for item in range(len(x)/2) ]
[(1, 2), (3, 4), (5, 6), (7, 8)]

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...