Reverse a string in Python two characters at a time (Network byte order)
If anybody is interested, this is the timing for all* the answers.
EDIT (had got it wrong the first time):
import timeit
import struct
string = "ABCDEFGH"
# Expected resutlt => GHEFCDAB
def rev(a):
new = ""
for x in range(-1, -len(a), -2):
new += a[x-1] + a[x]
return new
def rev2(a):
return "".join(reversed([a[i:i+2] for i in range(0, len(a), 2)]))
def rev3(a):
return "".join(map(str.__add__, a[-2::-2] ,a[-1::-2]))
def rev4(a):
return "".join(map("".join, reversed(zip(*[iter(a)]*2))))
def rev5(a):
n = len(a) / 2
fmt = '%dh' % n
return struct.pack(fmt, *reversed(struct.unpack(fmt, a)))
def rev6(a):
return "".join([a[x:x+2] for x in range(0,len(a),2)][::-1])
print "Greg Hewgill %f" %timeit.Timer("rev2(string)", "from __main__ import rev2, string").timeit(100000)
print "gnibbler %f" %timeit.Timer("rev3(string)", "from __main__ import rev3, string").timeit(100000)
print "gnibbler second %f" %timeit.Timer("rev4(string)", "from __main__ import rev4, string").timeit(100000)
print "Alok %f" %timeit.Timer("rev5(string)", "from __main__ import rev5, struct, string").timeit(100000)
print "elliot42 %f" %timeit.Timer("rev6(string)", "from __main__ import rev6, struct, string").timeit(100000)
print "me %f" %timeit.Timer("rev(string)", "from __main__ import rev, string").timeit(100000)
results for string = "ABCDEFGH"
:
Greg Hewgill 0.853000
gnibbler 0.428000
gnibbler second 0.707000
Alok 0.763000
elliot42 0.237000
me 0.200000
results for string = "ABCDEFGH"*5
:
Greg Hewgill 2.246000
gnibbler 0.811000
gnibbler second 1.205000
Alok 0.972000
elliot42 0.594000
me 0.584000
results for string = "ABCDEFGH"*10
:
Greg Hewgill 2.058000
gnibbler 1.178000
gnibbler second 1.926000
Alok 1.210000
elliot42 0.935000
me 1.082000
results for string = "ABCDEFGH"*100
:
Greg Hewgill 9.762000
gnibbler 9.134000
gnibbler second 14.782000
Alok 5.775000
elliot42 7.351000
me 18.140000
*Sorry @Lacrymology could not make your's work!
>>> import array
>>> s="abcdef"
>>> a=array.array('H',s)
>>> a.byteswap()
>>> a.tostring()
'badcfe'
Finish up by using a.reverse() instead of a.byteswap() if you wanted to swap element order rather than byte order.
I took the liberty of editing Trufa's benchmark script a bit. The modified script generated a graphical plot showing approximately linear scaling for all functions.
A concise way to do this is:
"".join(reversed([a[i:i+2] for i in range(0, len(a), 2)]))
This works by first breaking the string into pairs:
>>> [a[i:i+2] for i in range(0, len(a), 2)]
['AB', 'CD', 'EF', 'GH']
then reversing that, and finally concatenating the result back together.
Lots of fun ways to do this
>>> s="ABCDEFGH"
>>> "".join(map(str.__add__, s[-2::-2] ,s[-1::-2]))
'GHEFCDAB'