For example, having the string:
abcdefghijklmnopqrstuvwxyz
should result in something like this:
badcfehgjilknmporqtsvuxwzy
How do I even go about it?
I thought of something not very efficient, such as:
s = str(range(ord('a'), ord('z') + 1))
new_s = ''
for i in xrange(len(s)):
if i != 0 and i % 2 == 0:
new_s += '_' + s[i]
else:
new_s += s[i]
# Now it should result in a string such as 'ab_cd_ef_...wx_yz'
l = new_s.split('_')
for i in xrange(len(l)):
l[i] = l[i][::-1]
result = str(l)
Is there any better way ? Some way that is more efficient or more general so I could also go about it with 3 letters more easily ?
You can use zip()
function which woud return a list of tuples as [(b,a), (d,c), ...]
and the applying .join()
method to both the elements of the tuple and list as well.
a = "abcdefghijklmnopqrstuvwxyz"
# a[::2] = "acegikmoqsuwy"
# a[1::2] = "bdfhjlnprtvx"
print "".join("".join(i) for i in zip(a[1::2], a[::2]))
>>> badcfehgjilknmporqtsvuxwzy
EDIT: To handle the case of odd length strings, as suggested by @Ashwini and @TigerhawkT3, you may change the code as:
print "".join("".join(i) for i in zip(a2, a1)) + a[-1] if len(a)%2 else ''
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With