One solution without using any imports will be to convert string to an iterator and during the iteration fetch the next character by calling next on the iterator:
>>> s = "abcdefghijklmnopqrstuvwxyz"
>>> it = iter(s)
>>> ''.join(next(it, '') + c for c in it )
'badcfehgjilknmporqtsvuxwzy'
Timings:
>>> 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
But the calls to next
are actually slowing it down because for finding next
Python has to go to the builtins starting from local scope, let's cache it and try again:
>>> 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
But the fastest solution will be to use 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
@Joran's code is also very close to this one when used with a list instead of generator expression, but it creates two additional strings in memory:
>>> %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
Note that we should always feed a list
to str.join
if speed is a concern: https://stackoverflow.com/a/9061024/846892