2014-04-16 42 views
11

Mam więc Iterable 3-krotne, generowane leniwie. Próbuję dowiedzieć się, jak przekształcić to w 3 iterables, składające się z odpowiednio pierwszego, drugiego i trzeciego elementu krotek. Chciałbym jednak, żeby to było zrobione leniwie.Leniwie przetransponuj listę w Pythonie

Tak więc, na przykład, życzę [(1, 2, 3), (4, 5, 6), (7, 8, 9)] zostać przekształcony [1, 4, 7], [2, 5, 8], [3, 6, 9]. (Z wyjątkiem tego, że chcę iterables, a nie list).

Standardowy idiom zip(*data) nie działa, ponieważ rozpakowywanie argumentów rozszerza całą iterację. (Można to sprawdzić, zauważając, że zip(*((x, x+1, x+2) for x in itertools.count(step=3))) zawiesza się).

Najlepszym Mam wymyślić do tej pory to:

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]) 

To wydaje się działać. Ale wydaje się, że nie jest to czysty kod. I robi wiele z tego, co wydaje się niepotrzebną pracą.

+1

'' izip' z modułem itertools'? –

+0

Ponieważ masz działający kod, możesz uzyskać lepsze wyniki z recenzji kodu – wnnmaw

+0

Jak można się spodziewać, że twój nowy iterator otrzyma, powiedzmy, '7' z trzeciej krotki bez zużywania całej zewnętrznej iteracji? Twój 'tranpose' również się zawiesi, jeśli spróbujesz go na nieskończonym iteratorze typu' count'. – BrenBarn

Odpowiedz

3

Twój transpose jest dokładnie tym, czego potrzebujesz.

Przy każdym rozwiązaniu, które wybierzesz, będziesz musiał buforować nieużywane wartości (np. Aby dostać się do 7, musisz przeczytać 1-6 i przechowywać je w pamięci, gdy inne iterables poprosić o nich). tee robi już dokładnie taki rodzaj buforowania, więc nie trzeba go wdrażać samodzielnie.

Jedyna (minor) jest to, że bym go napisać nieco inaczej, unikając map i 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])