Ленько транспонировать список в Python

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

Итак, например, я хочу, чтобы [(1, 2, 3), (4, 5, 6), (7, 8, 9)] был превращен в [1, 4, 7], [2, 5, 8], [3, 6, 9]. (Кроме того, я хочу, чтобы итераторы не были списками.)

Стандартная идиома zip(*data) не работает, потому что распаковка аргументов расширяет всю итерабельность. (Вы можете проверить это, отметив, что zip(*((x, x+1, x+2) for x in itertools.count(step=3))) зависает.)

Самое лучшее, что я придумал до сих пор, следующее:

def transpose(iterable_of_three_tuples):
    teed = itertools.tee(iterable_of_three_tuples, 3)
    return map(lambda e: e[0], teed[0]), map(lambda e: e[1], teed[1]), map(lambda e: e[2], teed[2])

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

Ответ 1

Ваш transpose в значительной степени соответствует тому, что вам нужно.

С любым решением, которое вы выбрали бы, вам нужно будет буферизовать неиспользуемые значения (например, чтобы добраться до 7, вам нужно прочитать 1-6 и хранить их в памяти, когда другие итераторы запрашивают их), tee уже выполняет именно такую ​​буферизацию, поэтому нет необходимости реализовывать ее самостоятельно.

Единственное другое (второстепенное) дело в том, что я бы написал его несколько иначе, избегая map и lambda s:

def transpose(iterable_of_three_tuples):
    teed = itertools.tee(iterable_of_three_tuples, 3)
    return ( e[0] for e in teed[0] ),  ( e[1] for e in teed[1] ),  ( e[2] for e in teed[2] )