Jedno rozwiązanie bez użycia importu będzie przekonwertować ciąg do iteratora i podczas iteracji pobrać następny znak wywołując następny na iteracyjnej:
>>> s = "abcdefghijklmnopqrstuvwxyz"
>>> it = iter(s)
>>> ''.join(next(it, '') + c for c in it)
'badcfehgjilknmporqtsvuxwzy'
wczytywania:
>>> s = "abcdefghijklmnopqrstuvwxyz" * 10**5
>>> def func_next_no_cache(s):
it = iter(s)
return ''.join([next(it, '') + c for c in it])
...
>>> %timeit func_next_no_cache(s)
1 loops, best of 3: 291 ms per loop
Ale połączenia z next
spowalniają działanie, ponieważ do znalezienia next
Python ma udać się do poleceń wbudowanych, począwszy od zakresu lokalnej, niech buforować go i spróbuj jeszcze raz:
>>> def func_next_cache(s, next=next):
it = iter(s)
return ''.join([next(it, '') + c for c in it])
...
>>> %timeit func_next_cache(s)
1 loops, best of 3: 241 ms per loop
Ale najszybszym rozwiązaniem będzie użycie itertools.izip_longest
:
>>> from itertools import izip_longest
>>> def func_izip_l(s):
it = iter(s)
return "".join([b+a for a, b in izip_longest(it, it, fillvalue='')])
...
>>> %timeit func_izip_l(s)
1 loops, best of 3: 209 ms per loop
@ Kod Jøran jest również bardzo blisko do tego, gdy używana z listy zamiast wyrażenia generatora, ale tworzy dwa dodatkowe ciągi pamięć:
>>> %timeit "".join([b+a for a, b in izip_longest(s[::2], s[1::2], fillvalue="")])
1 loops, best of 3: 212 ms per loop
Uwaga że zawsze powinniśmy karmić list
do str.join
jeśli prędkość jest problemem: https://stackoverflow.com/a/9061024/846892
Czy długość nawet być zawsze? – thefourtheye
@thefourtheye No **. Nawiasem mówiąc, sposób, w jaki pisałem, wciąż działa na strunie o nierównej długości. – Jack
Czego oczekujesz wyniku, jeśli chcesz uzyskać 3 znaki? – thefourtheye