Inverser une chaîne en Python deux caractères à la fois (ordre des octets réseau)
Dites que vous avez cette chaîne:
ABCDEFGH
Et vous voulez l'Inverser pour qu'il devienne:
GHEFCDAB
Quelle serait la solution pythonique la plus efficace? J'ai essayé quelques choses différentes, mais elles ont toutes l'air horribles...
Merci d'avance!
Mise à Jour:
Au cas où quelqu'un serait intéressé, ce n'était pas pour les devoirs. J'avais un script qui traitait les données d'une capture réseau et les renvoyait sous la forme d'une chaîne d'octets hexadécimaux. Le problème était que les données étaient toujours dans le réseau de commande. En raison de la façon dont l'application a été écrite, Je ne voulais pas revenir en arrière et essayer d'utiliser say socket.htons, je voulais juste inverser la chaîne.
Malheureusement, mes tentatives semblaient si hideuses, je savais qu'il devait y avoir un meilleur moyen (une solution plus pythonique) - d'où ma question ici.
12 réponses
Concis façon de le faire est:
"".join(reversed([a[i:i+2] for i in range(0, len(a), 2)]))
Cela fonctionne en divisant d'abord la chaîne en paires:
>>> [a[i:i+2] for i in range(0, len(a), 2)]
['AB', 'CD', 'EF', 'GH']
Puis inverser cela, et enfin concaténer le résultat ensemble.
Beaucoup de façons amusantes de le faire
>>> s="ABCDEFGH"
>>> "".join(map(str.__add__, s[-2::-2] ,s[-1::-2]))
'GHEFCDAB'
, Si quelqu'un est intéressé, c'est le moment pour tous* les réponses.
EDIT (s'était trompé la première fois):
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)
Résultats pour string = "ABCDEFGH"
:
Greg Hewgill 0.853000
gnibbler 0.428000
gnibbler second 0.707000
Alok 0.763000
elliot42 0.237000
me 0.200000
Résultats pour string = "ABCDEFGH"*5
:
Greg Hewgill 2.246000
gnibbler 0.811000
gnibbler second 1.205000
Alok 0.972000
elliot42 0.594000
me 0.584000
Résultats pour string = "ABCDEFGH"*10
:
Greg Hewgill 2.058000
gnibbler 1.178000
gnibbler second 1.926000
Alok 1.210000
elliot42 0.935000
me 1.082000
Résultats pour string = "ABCDEFGH"*100
:
Greg Hewgill 9.762000
gnibbler 9.134000
gnibbler second 14.782000
Alok 5.775000
elliot42 7.351000
me 18.140000
* Désolé @Lacrymology n'a pas pu faire votre travail!
>>> import array
>>> s="abcdef"
>>> a=array.array('H',s)
>>> a.byteswap()
>>> a.tostring()
'badcfe'
Terminez en utilisant un. reverse() au lieu d'un.byteswap () si vous voulez échanger l'ordre des éléments plutôt que l'ordre des octets.
J'ai pris la liberté d'éditer un peu le script benchmark de Trufa. Le script Modifié a généré ungraphique montrant une mise à l'échelle approximativement linéaire pour toutes les fonctions.
Voici une forme générale. La taille du regroupement peut facilement être modifiée en un nombre différent de caractères à la fois. La longueur de chaîne doit être un multiple exact de la taille de regroupement
>>> "".join(map("".join, reversed(zip(*[iter("ABCDEFGH")]*2))))
'GHEFCDAB'
(Ceci est Python 2, cela ne fonctionnera pas dans 3)
Vous pouvez utiliser ceci, mais ne dites à personne que j'ai écrit ce code: -)
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')
st = "ABCDEFGH"
"".join([st[x:x+2] for x in range(0,len(st),2)][::-1])
EDIT: malédictions, apparemment 27 minutes plus lent qu'une autre affiche. Mais j'aime mieux la notation de tranche inverse.
Quelques informations supplémentaires sur la tranche inverse ici: "".join(inversé(val)) vs val[::-1]...qui est pythonic?
Juste un coup de feu
st = "ABCDEFGH"
s = [st[2*n:2*n+1] for n in range(len(st)/2)]
return s[::-1].join('')
Cela suppose que len (st) est pair, sinon changez cela en range(Len(st)/2+1) et je suis même sûr qu'il y a une meilleure façon de le faire en deux.
Si votre python se plaint de s[::-1] vous pouvez utiliser inversé(s)
Et encore une autre façon:
a = "ABCDEFGH"
new = ""
for x in range(-1, -len(a), -2):
new += a[x-1] + a[x]
print new
Cela ressemble à des devoirs. Voici donc une approche très peu orthodoxe que vous pourriez trouver intéressante:
>>> s = "ABCDEFGH"
>>> ''.join([s[::2][::-1][i]+s[::-2][i] for i in range(len(s[::2]))])
'GHEFCDAB'
Bonne Chance!
Et un autre Monte...
>>> rev = "ABCDEFGH"[::-1]
>>> ''.join([''.join(el) for el in zip(rev[1::2], rev[0::2])])
'GHEFCDAB'