この文字列があるとします。
ABCDEFGH
そして、次のようになるように逆にします。
GHEFCDAB
最も効率的な/ Pythonicソリューションは何でしょうか?私はいくつかの異なることを試しましたが、それらはすべてひどいように見えます...
前もって感謝します!
更新:
誰かが興味を持っている場合、これは宿題のためではありませんでした。ネットワークキャプチャからのデータを処理し、それを16進バイトの文字列として返すスクリプトがありました。問題は、データがまだネットワークの順序にあることでした。アプリの作成方法が原因で、戻ってたとえばsocket.htonsを使用したくなかったので、文字列を逆にしたかっただけです。
残念ながら、私の試みはとても恐ろしいようでした。もっと良い方法(よりPythonicな解決策)があるはずだとわかっていたので、ここで私の質問をします。
これを行うための簡潔な方法は次のとおりです。
"".join(reversed([a[i:i+2] for i in range(0, len(a), 2)]))
これは、最初に文字列をペアに分割することで機能します。
>>> [a[i:i+2] for i in range(0, len(a), 2)]
['AB', 'CD', 'EF', 'GH']
次にそれを逆にし、最後に結果を連結して戻します。
これを行うための楽しい方法がたくさん
>>> s="ABCDEFGH"
>>> "".join(map(str.__add__, s[-2::-2] ,s[-1::-2]))
'GHEFCDAB'
誰かが興味を持っているなら、これはすべての*答えのタイミングです。
編集(最初にそれを間違えた):
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)
の結果 string = "ABCDEFGH"
:
Greg Hewgill 0.853000
gnibbler 0.428000
gnibbler second 0.707000
Alok 0.763000
elliot42 0.237000
me 0.200000
の結果 string = "ABCDEFGH"*5
:
Greg Hewgill 2.246000
gnibbler 0.811000
gnibbler second 1.205000
Alok 0.972000
elliot42 0.594000
me 0.584000
の結果 string = "ABCDEFGH"*10
:
Greg Hewgill 2.058000
gnibbler 1.178000
gnibbler second 1.926000
Alok 1.210000
elliot42 0.935000
me 1.082000
の結果 string = "ABCDEFGH"*100
:
Greg Hewgill 9.762000
gnibbler 9.134000
gnibbler second 14.782000
Alok 5.775000
elliot42 7.351000
me 18.140000
*申し訳ありませんが@Lacrymologyはあなたの仕事をすることができませんでした!
>>> import array
>>> s="abcdef"
>>> a=array.array('H',s)
>>> a.byteswap()
>>> a.tostring()
'badcfe'
バイトオーダーではなく要素オーダーを交換したい場合は、a.byteswap()の代わりにa.reverse()を使用して終了します。
Trufaのベンチマークスクリプトを少し自由に編集しました。 変更されたスクリプト 生成された グラフィカルプロット すべての関数のほぼ線形のスケーリングを示しています。
これが一般的な形式です。グループ化のサイズは、一度に異なる文字数に簡単に変更できます。文字列の長さは、グループ化サイズの正確な倍数である必要があります
>>> "".join(map("".join, reversed(Zip(*[iter("ABCDEFGH")]*2))))
'GHEFCDAB'
(これはPython 2、3では機能しません)
st = "ABCDEFGH"
"".join([st[x:x+2] for x in range(0,len(st),2)][::-1])
編集:呪い、明らかに別のポスターより27分遅い。しかし、私は逆スライス表記の方が好きです。
リバーススライスの詳細については、こちらをご覧ください: ""。join(reversed(val))vs val [::-1] ...これはpythonicですか?
これを使用することはできますが、私がこのコードを書いた人には言わないでください:-)
import struct
def pair_reverse(s):
n = len(s) / 2
fmt = '%dh' % n
return struct.pack(fmt, *reversed(struct.unpack(fmt, s)))
pair_reverse('ABCDEFGH')
私の友人 Rob 美しい再帰的解決策を指摘しました:
def f(s):
return "" if not s else f(s[2:]) + s[:2]
そしてさらに別の方法:
a = "ABCDEFGH"
new = ""
for x in range(-1, -len(a), -2):
new += a[x-1] + a[x]
print new
これは、上記および現在のPython 3構文:
def reverse_hex(hex_string):
if isinstance(hex_string, str):
input_is_string = True
hex_string = hex_string.encode()
a = array.array('H', hex_string)
a.reverse()
output = a.tobytes()
if input_is_string:
return output.decode()
else:
return output
私はこのソリューションが最も単純で最も近いので最も好きです:
import struct
hex = struct.pack('<I', 0x41424344) #ABCD
print(hex) # BCDA
そして別の人が乗る...
>>> rev = "ABCDEFGH"[::-1]
>>> ''.join([''.join(el) for el in Zip(rev[1::2], rev[0::2])])
'GHEFCDAB'
ただのショット
st = "ABCDEFGH"
s = [st[2*n:2*n+1] for n in range(len(st)/2)]
return s[::-1].join('')
これは、len(st)が偶数であることを前提としています。そうでない場合は、range(len(st)/ 2 + 1)に変更してください。これを、2つに分割するより良い方法があると確信しています。
pythonがs [::-1]について文句を言う場合は、reversed(s)を使用できます
これは宿題のように見えます。それで、あなたが面白いと思うかもしれない非常に非正統的なアプローチがここにあります:
>>> s = "ABCDEFGH"
>>> ''.join([s[::2][::-1][i]+s[::-2][i] for i in range(len(s[::2]))])
'GHEFCDAB'
幸運を!