Mam listę krotek z 2 elementami i chciałbym przekonwertować je na 2 listy, w których pierwsza zawiera pierwszą pozycję w każdej krotce, a druga lista zawiera drugą pozycję.
Na przykład:
original = [('a', 1), ('b', 2), ('c', 3), ('d', 4)]
# and I want to become...
result = (['a', 'b', 'c', 'd'], [1, 2, 3, 4])
Czy istnieje wbudowana funkcja, która to robi?
Odpowiedzi:
zip
jest własną odwrotnością! Pod warunkiem, że korzystasz ze specjalnego * operatora.Działa to poprzez wywołanie
zip
argumentów:… Z wyjątkiem argumentów przekazywanych
zip
bezpośrednio (po przekonwertowaniu na krotkę), więc nie trzeba się martwić, że liczba argumentów stanie się zbyt duża.źródło
zip([], [])
ten sposób cię nie dostanie[], []
. Dostaje cię[]
. Jeśli tylko ...zip
działa dokładnie tak samo w Pythonie 3, z tym wyjątkiem, że zwraca iterator zamiast listy. Aby uzyskać taki sam wynik, jak powyżej, wystarczy zawinąć wywołanie zip w listę:list(zip(*[('a', 1), ('b', 2), ('c', 3), ('d', 4)]))
wyświetli[('a', 'b', 'c', 'd'), (1, 2, 3, 4)]
list
s są w porządku. Ale jeśli spróbujesz realizować pełny rezultat naraz (przezlist
ifying wynikzip
), można użyć dużo pamięci (ponieważ wszystkie tetuple
s muszą być tworzone na raz). Jeśli możesz po prostu powtórzyć wynikzip
bezlist
ifying, zaoszczędzisz dużo pamięci. Jedynym innym problemem jest to, czy dane wejściowe zawierają wiele elementów; istnieje koszt, że musi rozpakować je wszystkie jako argumenty izip
będzie musiał utworzyć i przechowywać iteratory dla wszystkich. To tylko prawdziwy problem z bardzo długimilist
s (pomyśl o setkach tysięcy elementów lub więcej).Ty też możesz to zrobić
Powinno być lepiej skalowane. Zwłaszcza jeśli Python robi dobrze, jeśli nie jest to konieczne, aby nie rozszerzać listy.
(Nawiasem mówiąc, tworzy 2-krotkę (parę) list, a nie listę krotek, jak to
zip
robi.)Jeśli generatory zamiast rzeczywistych list są w porządku, to by to zrobiło:
Generatory nie przeszukują listy, dopóki nie poprosisz o każdy element, ale z drugiej strony zachowują odniesienia do oryginalnej listy.
źródło
zip(*x)
wersja.zip(*x)
wymaga tylko jednego przejścia przez pętlę i nie zużywa elementów stosu.zip
jeśli przypadek użycia polega na tym, że transponowane dane są natychmiast wykorzystywane i odrzucane, podczas gdy oryginalne listy pozostają w pamięci znacznie dłużej.Jeśli masz listy, które nie są tej samej długości, możesz nie chcieć używać zip zgodnie z odpowiedzią Patricks. To działa:
Ale przy różnych listach długości zip obcina każdy element do długości najkrótszej listy:
Możesz użyć mapy bez funkcji do wypełnienia pustych wyników brakiem:
zip () jest jednak nieznacznie szybszy.
źródło
izip_longest
zip_longest
dla użytkowników python3.Lubię używać
zip(*iterable)
(który jest fragmentem kodu, którego szukasz) w moich programach, ponieważ:Uważam, że jest
unzip
bardziej czytelny.źródło
Daje krotkę list jak w pytaniu.
Rozpakowuje dwie listy.
źródło
Naiwne podejście
działa dobrze w przypadku iteracji skończonej (np. sekwencji takich jak
list
/tuple
/str
) (potencjalnie nieskończonych) iteracji, które można zilustrować jakgdzie
n in ℕ
,a_ij
odpowiadaj
-temu elementowii
-tej iterowalnej,a po złożeniu wniosku
transpose_finite_iterable
otrzymujemyPyton przykład takiego przypadku
a_ij == j
,n == 2
Ale nie możemy użyć
transpose_finite_iterable
ponownie, aby powrócić do struktury oryginału,iterable
ponieważresult
jest nieskończoną iteracją iteracji skończonych (tuple
w naszym przypadku):Jak więc poradzić sobie z tą sprawą?
... i oto nadchodzi
deque
Po przyjrzeniu się dokumentom
itertools.tee
funkcji istnieje przepis w języku Python, który z pewnymi modyfikacjami może pomóc w naszym przypadkuSprawdźmy
Synteza
Teraz możemy zdefiniować ogólną funkcję do pracy z iterowalnymi elementami iteracyjnymi, z których niektóre są skończone, a inne są potencjalnie nieskończone za pomocą
functools.singledispatch
dekoratora takiego jakktóre można uznać za własną odwrotność (matematycy nazywają tego rodzaju funkcje „inwolucjami” ) w klasie operatorów binarnych w stosunku do skończonych niepustych iteratów.
Jako bonus
singledispatch
ing możemy obsługiwaćnumpy
tablice takie jaka następnie użyj go jak
Uwaga
Ponieważ
transpose
zwroty iteratory i jeśli ktoś chce miećtuple
zlist
s jak w PO - to może być wykonane dodatkowo zmap
wbudowaną funkcję jakReklama
Dodałem uogólnione rozwiązanie do
lz
pakietu z0.5.0
wersji, z której można korzystać jakPS
Nie ma rozwiązania (przynajmniej oczywistego) dla obsługi potencjalnie nieskończonej iteracji potencjalnie nieskończonych iteracji, ale ten przypadek jest jednak mniej powszechny.
źródło
To tylko inny sposób, aby to zrobić, ale bardzo mi pomogło, więc piszę tutaj:
Posiadanie tej struktury danych:
Wynikające z:
Moim zdaniem bardziej pythonowy sposób na rozpakowanie go i powrót do oryginału:
Ale to zwraca krotkę, więc jeśli potrzebujesz listy, możesz użyć:
źródło
Rozważ użycie more_itertools.unzip :
źródło
Ponieważ zwraca krotki (i może zużywać mnóstwo pamięci),
zip(*zipped)
sztuczka wydaje mi się bardziej sprytna niż przydatna.Oto funkcja, która da ci odwrotność zip.
źródło
Żadna z poprzednich odpowiedzi nie zapewnia wydajnego wyniku, który jest krotką list , a nie listą krotek . W przypadku tych pierwszych możesz używać
tuple
zmap
. Oto różnica:Ponadto większość poprzednich rozwiązań zakłada Python 2.7, w którym
zip
zwraca listę zamiast iteratora.W przypadku Python 3.x musisz przekazać wynik do funkcji takiej jak
list
lubtuple
do wyczerpania iteratora. W przypadku iteratorów energooszczędnych można pominąć zewnętrznelist
ituple
wzywa do odpowiednich rozwiązań.źródło
Chociaż
zip(*seq)
jest to bardzo przydatne, może być nieodpowiednie dla bardzo długich sekwencji, ponieważ stworzy krotkę wartości, które zostaną przekazane. Na przykład pracowałem z układem współrzędnych z ponad milionem wpisów i stwierdziłem, że tworzenie go jest znacznie szybsze sekwencje bezpośrednio.Ogólne podejście wyglądałoby mniej więcej tak:
Ale w zależności od tego, co chcesz zrobić z wynikiem, wybór kolekcji może mieć duże znaczenie. W moim przypadku użycie zestawów i brak wewnętrznej pętli jest zauważalnie szybsze niż wszystkie inne podejścia.
I, jak zauważyli inni, jeśli robisz to z zestawami danych, warto zamiast tego używać kolekcji Numpy lub Pandas.
źródło
Chociaż tablice i pandy numpy mogą być preferowane, ta funkcja imituje zachowanie
zip(*args)
wywołane jakounzip(args)
.Umożliwia przekazywanie generatorów w
args
miarę iteracji wartości. Udekorujcls
i / lubmain_cls
mikro zarządzaj inicjalizacją kontenera.źródło