2010-04-20 5 views
2

Je souhaite réduire ou développer des sous-séquences d'une listeManière élégante de réduire ou de développer des sous-séquences d'une liste en Python?

Par ex. ['A', 'B', 'D', 'E', 'H'] -> ['AB', 'DE', 'H'] et vice versa

EDIT: l'exemple ci-dessus peut provoquer un malentendu. ce qui suit est meilleur:

par exemple. ['foo', 'bar', 'wtf'] <-> ['baz', 'wtf']

actuellement j'ai écrit un code laid comme:

while True: 
    for i, x in enumerate(s): 
    if x == 'foo' and s[i+1] == 'bar': 
     s[i:i+2] = 'baz' 
     break 
    else: 
    break 

Pour les personnes qui demandent « pourquoi cette chose »:

En fait, je travaille sur un compilateur d'optimisation, ce qui est la partie judas . L'écriture de motifs est un peu ennuyante.

P.S. J'ai trouvé le code suivant fonctionne, mais un peu ridicule, pourquoi énumérer connaître notre modification?

s = ['foo', 'bar', 'wtf', 'foo', 'bar', 'wtf', 'foo', 'bar', 'wtf'] 

def collapse(): 
    for i, x in enumerate(s): 
     if s[i] == 'foo' and s[i+1] == 'bar': 
      s[i:i+2] = ['baz'] 

def expand(): 
    for i, x in enumerate(s): 
     if s[i] == 'baz': 
      s[i:i+1] = ['foo', 'bar'] 

collapse() 
print s 
expand() 
print s 
+0

Comment "foo" et "bar" deviennent "baz"? – SilentGhost

+0

juste trouver foo suivi par une barre, et les tourner à baz – inv

Répondre

1

Voir itertools. Plus précisément, voici une recette pour plus ou moins ce que vous voulez (en fait, ce que je croyais que tu voulais après votre type de message original trompeur!):

from itertools import tee, izip 

def pairwise(iterable): 
    "s -> (s0,s1), (s1,s2), (s2, s3), ..." 
    a, b = tee(iterable) 
    next(b, None) 
    return izip(a, b) 

Cela renverra tuples que vous pouvez join().

Pour annuler cela, il suffit de join() votre dernière séquence et de parcourir les différents éléments (caractères).

Je vais essayer de trouver une réponse à votre nouvelle/vraie question.

+0

désolé je ne comprends pas le point par rapport à ma question :(peut-être l'exemple est trop mauvais.Je l'ai édité.S'il vous plaît vérifier à nouveau – inv

+0

@forgot, à la place d'utiliser l'indexation pour obtenir l'élément suivant, utilisez ceci pour faire une recherche automatique, mais cela devient un peu compliqué car vous devez ignorer ce que vous ajoutez à l'étape suivante, mais c'est la vie. –

+0

@Mike Graham, absolument, triste mais vrai :) – inv

0

Je pense que votre chemin avec enumerate est plutôt bon. Enumerate est capable de suivre les modifications car il crée un générateur qui utilise un itérateur du tableau que vous avez entré. Le problème que je vois est que si vous changez votre tableau à être:

s = ['foo', 'bar', 'wtf', 'foo', 'bar', 'wtf', 'foo'] 

alors le dernier « foo » qui ne dispose pas d'un « bar » vous donnera une exception lorsque votre code tente de regarder au-delà de l'élément la fin du tableau. Je ne sais pas encore comment résoudre ce problème, car mes tentatives n'ont pas été couronnées de succès.

Edit:

Il ne peut pas être très élégant, mais ce code pour la fonction collapse() fonctionnera même sur le cas ci-dessus:

def collapse(): 
    i = 1 
    L = len(s) 
    while i < L: 
     if s[i-1] == 'foo' and s[i] == 'bar': 
      s[i-1:i+1] = ['baz'] 
      L -= 1 
     i += 1 
+0

Les gens ont certainement tous les droits de downvote ma réponse, mais pourquoi ma réponse était si mauvaise? –

+0

Je n'ai pas encore voté. Vous répondez n'est pas mauvais, mais semble que les codeurs python n'aiment pas garder index de cette façon. btw vous pouvez simplement remplacer la variable L par 'while i inv

+0

@forgot oui, vous pouvez le remplacer si vous le souhaitez. J'ai pensé à le mettre comme ça au début, mais je suis à peu près certain que la fonction len() serait un peu plus lente. Si vous envisagez de l'utiliser comme un compilateur, j'ai pensé que la vitesse pourrait être importante. Cependant, j'avoue que c'est une optimisation prématurée (ce qui est mal). –

2

Je ne dirais pas cela beaucoup mieux, mais il est un C'est une façon différente de le faire, et il gère également le bizarrement que souligne Justin.(Je suis plus intéressé à trouver une suite dans une liste, et je ne pouvais pas trouver une bonne fonction sur Google)

def findsubseq(L, subseq): 
    if not subseq: return # just die on zero-len input 
    i = -1 
    try: 
     while True: 
      i = L.index(subseq[0], i+1) 
      for j in range(1, len(subseq)): 
       if L[i+j] != subseq[j]: 
        break 
      else: 
       yield i 
    except ValueError: pass 
    except IndexError: pass 

def replace(target, changethis, tothis): 
    subseqs = [x for x in findsubseq(target, changethis)] 
    subseqs.reverse() 
    for i in subseqs: 
     target[i:i+len(changethis)] = tothis 
def collapse(): 
    global s 
    replace(s, ['foo', 'bar'], ['baz']) 
def expand(): 
    global s 
    replace(s, ['baz'], ['foo', 'bar']) 

s = ['foo', 'bar', 'wtf', 'foo', 'bar', 'wtf', 
     'foo', 'bar', 'bar', 'bar', 'foo'] 
print s 
collapse() 
print s 
expand() 
print s 

C:\Scripts>subseq.py 
['foo', 'bar', 'wtf', 'foo', 'bar', 'wtf', 'foo', 'bar', 'bar', 'bar', 'foo'] 
['baz', 'wtf', 'baz', 'wtf', 'baz', 'bar', 'bar', 'foo'] 
['foo', 'bar', 'wtf', 'foo', 'bar', 'wtf', 'foo', 'bar', 'bar', 'bar', 'foo'] 

Modifier: généralisé à une simple fonction de remplacement

+0

Je me demandais si cela pourrait être rediffusé pour que le générateur fournisse des indices à remplacer au fur et à mesure qu'il bouge plutôt que 1) tout, 2) les retournant pour éviter de les rétrécir/grossir, 3) le remplacer, mais le générateur pour ajuster où il cherche ('list.index()') si 'changethis' est vide, ce qui pourrait amener' changethis == tothis' à le bloquer. Facilement remédié, mais cela reste comme un exercice pour le lecteur. –

Questions connexes