2011-05-03 89 views
29

说你有这个字符串两个字:反向Python中的字符串在同一时间(网络字节顺序)

ABCDEFGH 

而且要扭转这种局面,使之成为:

GHEFCDAB 

什么将是最有效的/ pythonic解决方案?我尝试了一些不同的东西,但他们都看起来很可怕...

在此先感谢!

更新

如果任何人的兴趣,这不是功课。我有一个脚本来处理来自网络捕获的数据并将其作为一串十六进制字节返回。问题是数据仍然处于网络顺序。由于该应用程序的编写方式,我不想回过头去尝试使用socket.htons,我只是想反转字符串。

不幸的是,我的尝试似乎太可怕了,我知道必须有更好的方法(更pythonic解决方案) - 因此我的问题在这里。

+2

我们可以看一下你已经尝试了什么,也许我们可以帮助改善它。 – Trufa 2011-05-03 01:52:06

+5

这是功课吗? – jterrace 2011-05-03 01:54:14

+0

恐怕我没有它的方便(它在工作),但它确实很狡猾。目前我正在使用一个非常奇怪的循环结构。我很乐意提供一个简单的解决方案来替换我的混乱:) – PeterM 2011-05-03 01:55:02

回答

25

甲简明的方式来做到这一点是:

"".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'] 

然后反向的是,最后串联重一起回去。

+2

lol我花了一分钟写了大约12行,然后我刷新了页面,看到了你的。 – 2011-05-03 02:03:00

4

这是一般形式。分组的大小一次可以轻松更改为不同数量的字符。字符串长度应该是分组大小

>>> "".join(map("".join, reversed(zip(*[iter("ABCDEFGH")]*2)))) 
'GHEFCDAB' 

的整数倍(这是Python 2中,它不会在3工作)

+1

爱用拉链和地图。我不熟悉这个星号符号,你能解释一下吗? – laher 2011-05-03 02:11:20

+1

@ amir75 http://docs.python.org/tutorial/controlflow.html#unpacking-argument-lists – 2011-05-03 02:15:07

+0

你能解释一下这个解决方案吗?就像在发生什么事情一样? – 2011-05-03 02:17:53

13

很多有趣的方式来做到这一点

>>> s="ABCDEFGH" 
>>> "".join(map(str.__add__, s[-2::-2] ,s[-1::-2])) 
'GHEFCDAB' 
+0

ohhhh 可爱。 是的,正如他所说,有很多好玩的方法可以做到这一点 – Lacrymology 2011-05-03 02:11:25

+0

+1。这一个非常整齐,因为它一分为二,并且不使用字符串的长度。 – Macke 2011-05-05 09:50:25

0

只是一个拍

st = "ABCDEFGH" 
s = [st[2*n:2*n+1] for n in range(len(st)/2)] 
return s[::-1].join('') 

这个假设LEN(ST)为偶数,否则它改成范围(LEN(ST)/ 2 +1),我甚至确定有更好的方法可以分成两部分。

如果你的Python抱怨S [:: - 1]你可以用相反的(S)

3

您可以使用此,但不要告诉任何人,我写了这个代码:-)

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') 
0

而另一种方式:

a = "ABCDEFGH" 
new = "" 

for x in range(-1, -len(a), -2): 
    new += a[x-1] + a[x] 

print new 
2
st = "ABCDEFGH" 
"".join([st[x:x+2] for x in range(0,len(st),2)][::-1]) 

编辑:诅咒,显然比另一个海报慢27分钟。但我更喜欢反向切片符号。

在反向片在这里的一些详细信息:"".join(reversed(val)) vs val[::-1]...which is pythonic?

+0

对我来说似乎也是最pythonic,而且速度很快。列表切片是非常好的优化,虽然我很少看到它用于代替reverse()= /。 – TyrantWave 2011-05-03 09:18:07

10

如果有人有兴趣,这是所有*的答案的时机。

EDIT(曾听错了第一次):

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不能让你的工作!

+0

我喜欢你的经验主义=)=) – elliot42 2011-05-03 04:07:39

+0

@ elliot42:那是因为你是最快的! :P – Trufa 2011-05-03 04:09:03

+0

你应该使用'string'而不用单引号括起来(并且在你的setup语句中输入名字'string')。否则,你正在检查在常量字符串“string”上运行的时间。顺便说一句,我的方法是最长的字符串(我的电脑上约50个字符或更多)。但是我不确定如果我以这种方式编写函数,如果它是生产代码:-)。 – 2011-05-03 04:23:00

0

这看起来像家庭作业。所以这里有一个非正统的方法,你可能会感兴趣:

>>> s = "ABCDEFGH" 
>>> ''.join([s[::2][::-1][i]+s[::-2][i] for i in range(len(s[::2]))]) 
'GHEFCDAB' 

祝你好运!

6
>>> import array 
>>> s="abcdef" 
>>> a=array.array('H',s) 
>>> a.byteswap() 
>>> a.tostring() 
'badcfe' 

如果您想交换元素顺序而不是字节顺序,请使用a.reverse()而不是a.byteswap()完成。

我冒昧地编辑了特鲁法的基准脚本。 modified script生成了一个graphical plot,显示了所有功能的近似线性缩放。

+0

整洁的模块找!对那个不熟悉。 – elliot42 2011-05-05 09:53:15

1

我的朋友Rob指出了一个美丽的递归解决方案:

def f(s): 
    return "" if not s else f(s[2:]) + s[:2] 
0

和另一沾到...

>>> rev = "ABCDEFGH"[::-1] 
>>> ''.join([''.join(el) for el in zip(rev[1::2], rev[0::2])]) 
'GHEFCDAB'