I am a newbie and seeking for the Zen of Python :) Today's koan was finding the most Pythonesq way to solve the following problem:
Permute the letters of a string pairwise, e.g.
input: 'abcdefgh' output: 'badcfehg'
I am a newbie and seeking for the Zen of Python :) Today's koan was finding the most Pythonesq way to solve the following problem:
Permute the letters of a string pairwise, e.g.
input: 'abcdefgh' output: 'badcfehg'
I'd go for:
s="abcdefgh"
print "".join(b+a for a,b in zip(s[::2],s[1::2]))
s[start:end:step] takes every step'th letter, zip matches them up pairwise, the loop swaps them, and the join gives you back a string.
Since in Python, every string is also an iterable, itertools comes in handy here.
In addition to the functions itertools provides, the documentation also supplies lots of recipes.
from itertools import izip_longest
# From Python 2.6 docs
def grouper(n, iterable, fillvalue=None):
"grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
args = [iter(iterable)] * n
return izip_longest(fillvalue=fillvalue, *args)
Now you can use grouper to group the string by pairs, then reverse the pairs, then join them back into a string.
pairs = grouper(2, "abcdefgh")
reversed_pairs = [''.join(reversed(item)) for item in pairs]
print ''.join(reversed_pairs)
''.join(s[i+1] + s[i] for i in range(0,len(s),2))
Yes, I know it's less pythonic for using range, but it's short, and I probably don't have to explain it for you to figure out what it does.
my personal favorite to do stuff pairwise:
def pairwise( iterable ):
it = iter(iterable)
return zip(it, it) # zipping the same iterator twice produces pairs
output = ''.join( b+a for a,b in pairwise(input))
I just noticed that none of the existing answers work if the length of the input is odd. Most of the answers lose the last character. My previous answer throws an exception.
If you just want the last character tacked onto the end, you could do something like this:
print "".join(map(lambda a,b:(b or '')+a, s[::2], s[1::2]))
or in 2.6 and later:
print "".join(b+a for a,b in izip_longest(s[::2],s[1::2], fillvalue=''))
This is based on Anthony Towns's answer, but uses either map
or izip_longest
to make sure the last character in an odd-length string doesn't get discarded. The (b or '')
bit in the map
version is to convert the None
that map
pads with into ''
.
This may look a little scary, but I think you'd learn a lot deciphering the following idiom:
s = "abcdefgh"
print ''.join(b+a for a,b in zip(*[iter(s)]*2))