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.

29
demandé sur PeterM 2011-05-03 05:48:53

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.

27
répondu Greg Hewgill 2011-05-03 01:59:03

Beaucoup de façons amusantes de le faire

>>> s="ABCDEFGH"
>>> "".join(map(str.__add__, s[-2::-2] ,s[-1::-2]))
'GHEFCDAB'
13
répondu John La Rooy 2011-05-03 02:07:52

, 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!

10
répondu Trufa 2011-05-03 05:11:18
>>> 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.

6
répondu Yann Vernier 2016-09-22 08:00:49

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)

4
répondu John La Rooy 2013-10-16 14:07:52

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')
3
répondu Alok Singhal 2011-05-03 02:17:23
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?

2
répondu elliot42 2017-05-23 12:00:55

Mon ami Rob souligné une belle solution récursive:

def f(s):
    return "" if not s else f(s[2:]) + s[:2]
1
répondu elliot42 2017-05-23 12:16:21

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)

0
répondu Lacrymology 2011-05-03 02:10:31

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
0
répondu Trufa 2011-05-03 02:23:30

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!

0
répondu inspectorG4dget 2011-05-03 04:06:20

Et un autre Monte...

>>> rev = "ABCDEFGH"[::-1]
>>> ''.join([''.join(el) for el in zip(rev[1::2], rev[0::2])])
'GHEFCDAB'
0
répondu dansalmo 2013-05-19 16:21:23