Jaki jest najbardziej pytoniczny sposób połączenia dwóch strun?
Na przykład:
Wejście:
u = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
l = 'abcdefghijklmnopqrstuvwxyz'
Wynik:
'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'
python
string
python-2.7
python-3.x
Brandon Deo
źródło
źródło
Odpowiedzi:
Dla mnie najbardziej pythoniczny * sposób to następujący, który prawie robi to samo, ale używa
+
operatora do łączenia poszczególnych znaków w każdym ciągu:Jest również szybszy niż korzystanie z dwóch
join()
połączeń:Istnieją szybsze metody, ale często zaciemniają one kod.
Uwaga: Jeśli dwa ciągi wejściowe nie mają takiej samej długości, dłuższy zostanie obcięty jako
zip
zatrzymanie iteracji na końcu krótszego ciągu. W tym przypadku zamiastzip
jednego należy użyćzip_longest
(izip_longest
w Pythonie 2) zitertools
modułu, aby upewnić się, że oba ciągi są całkowicie wyczerpane.* Cytat z Zen of Python : liczy się czytelność .
Pythonic = czytelność dla mnie;
i + j
jest po prostu łatwiej analizowany wizualnie, przynajmniej dla moich oczu.źródło
"".join([i + j for i, j in zip(l1, l2)])
i na pewno będzie najszybszy"".join(map("".join, zip(l1, l2)))
jest jeszcze szybszy, choć niekoniecznie bardziej pythonowy.Szybsza alternatywa
Inny sposób:
Wynik:
Prędkość
Wygląda na to, że jest szybszy:
niż najszybsze dotychczas rozwiązanie:
Również w przypadku większych strun:
Python 3.5.1.
Wariacja dla strun o różnych długościach
Krótszy określa długość (
zip()
ekwiwalent)Wynik:
Dłuższy określa długość (
itertools.zip_longest(fillvalue='')
ekwiwalent)Wynik:
źródło
Z
join()
izip()
.źródło
''.join(itertools.chain.from_iterable(zip(u, l)))
zip
zatrzymanie, gdy krótsza lista została w pełni iterowana.itertools.zip_longest
można użyć, jeśli stanie się to problemem.W Pythonie 2, zdecydowanie szybszym sposobem robienia rzeczy, przy ~ 3-krotnej szybkości cięcia list dla małych łańcuchów i ~ 30-krotnie dla długich, jest
To jednak nie zadziała w Pythonie 3. Możesz zaimplementować coś takiego
ale do tego czasu straciłeś już korzyści wynikające z krojenia list dla małych ciągów (wciąż jest to 20 razy szybsze dla długich łańcuchów), a to jeszcze nie działa nawet dla znaków spoza ASCII.
FWIW, jeśli są w ten sposób na masywne ciągi i trzeba w każdym cyklu, a z jakiegoś powodu trzeba użyć ciągi Pythona ... oto jak to zrobić:
Pomoże też w tym specjalna obudowa, stosowana w zwykłym przypadku mniejszych typów. FWIW, jest to tylko 3-krotnie szybsze cięcie list dla długich ciągów i współczynnik 4 do 5 wolniejsze dla małych.
Tak czy inaczej wolę
join
rozwiązania, ale skoro w innym miejscu wspomniano o czasach , pomyślałem, że równie dobrze mogę się przyłączyć.źródło
Jeśli chcesz najszybszy sposób, możesz połączyć itertools z
operator.add
:Ale łączenie
izip
ichain.from_iterable
znowu jest szybszeIstnieje również zasadnicza różnica między
chain(*
ichain.from_iterable(...
.Nie ma czegoś takiego jak generator z łączeniem, przepuszczenie jednego będzie zawsze wolniejsze, ponieważ Python najpierw zbuduje listę przy użyciu zawartości, ponieważ wykonuje dwa przejścia przez dane, jeden do określenia potrzebnego rozmiaru, a drugi do faktycznego wykonania połączenie, które nie byłoby możliwe przy użyciu generatora:
join.h :
Również jeśli masz ciągi o innej długości i nie chcesz stracić danych, możesz użyć izip_longest :
W przypadku Pythona 3 nazywa się to
zip_longest
Ale w przypadku Pythona2 sugestia Veedrac jest zdecydowanie najszybsza:
źródło
list
?? jest niepotrzebne"".join(list(...))
give me 6.715280318699769 and timeit the"".join(starmap(...))
give me 6.46332361384313"".join(list(starmap(add, izip(l1,l2))))
jest wolniejszy niż"".join(starmap(add, izip(l1,l2)))
. Uruchamiam test na moim komputerze w pythonie 2.7.11 i pythonie 3.5.1 nawet w wirtualnej konsoli www.python.org z pythonem 3.4.3 i wszyscy mówią to samo i uruchamiam go kilka razy i zawsze to samoMożesz to również zrobić za pomocą
map
ioperator.add
:Wyjście :
To, co robi mapa, to pobiera każdy element z pierwszej iterowalnej
u
i pierwsze elementy z drugiej iterowalnejl
i stosuje funkcję dostarczoną jako pierwszy argumentadd
. Następnie dołącz po prostu dołącz do nich.źródło
Odpowiedź Jima jest świetna, ale oto moja ulubiona opcja, jeśli nie masz nic przeciwko kilku importom:
źródło
Wiele z tych sugestii zakłada, że struny mają jednakową długość. Może to obejmuje wszystkie rozsądne przypadki użycia, ale przynajmniej wydaje mi się, że możesz chcieć pomieścić również struny o różnych długościach. A może tylko ja uważam, że siatka powinna działać trochę tak:
Można to zrobić w następujący sposób:
źródło
Lubię używać dwóch
for
, nazwy zmiennych mogą dać wskazówkę / przypomnienie o tym, co się dzieje:źródło
Aby dodać kolejne, bardziej podstawowe podejście:
źródło
Trochę nie-pythonicznie wydaje się nie brać pod uwagę odpowiedzi na podwójne rozumienie listy tutaj, aby obsłużyć n string z wysiłkiem O (1):
gdzie
all_strings
jest lista ciągów, które chcesz przeplatać. W twoim przypadkuall_strings = [u, l]
. Pełny przykład użycia wyglądałby następująco:Jak wiele odpowiedzi, najszybciej? Prawdopodobnie nie, ale proste i elastyczne. Ponadto, bez zbyt dużej złożoności, jest to nieco szybsze niż akceptowana odpowiedź (ogólnie dodawanie ciągów jest nieco powolne w Pythonie):
źródło
Potencjalnie szybsze i krótsze niż obecne wiodące rozwiązanie:
Jeśli chodzi o szybkość strategii, należy zrobić jak najwięcej na poziomie C. Ta sama poprawka zip_longest () dla nierównych łańcuchów i wychodziłaby z tego samego modułu co chain (), więc nie mogę tam dać mi zbyt wielu punktów!
Inne rozwiązania, które wymyśliłem po drodze:
źródło
Możesz użyć 1
iteration_utilities.roundrobin
lub
ManyIterables
klasa z tego samego pakietu:1 Jest to z biblioteki trzeciej mam napisane:
iteration_utilities
.źródło
Użyłbym zip (), aby uzyskać czytelny i łatwy sposób:
źródło