2010-06-02 8 views
0

J'ai une liste de peut-être une centaine d'éléments qui est en fait un e-mail avec chaque ligne en tant qu'élément. La liste est légèrement variable car les lignes qui contiennent un \ n sont placées dans un élément séparé, donc je ne peux pas simplement découper en utilisant des valeurs fixes. J'ai besoin essentiellement d'une phrase de départ et d'arrêt variable (doit être une recherche partielle aussi parce que l'une de mes phrases de départ pourrait effectivement être Total Cost: $13.43 alors je voudrais simplement utiliser Total Cost:.) Même chose avec la phrase de fin. Je ne souhaite pas non plus inclure les phrases de début/de fin dans la liste renvoyée. En résumé:Python: Trouver X à Y dans une liste de chaînes

>>> email = ['apples','bananas','cats','dogs','elephants','fish','gee'] 
>>> start = 'ban' 
>>> stop = 'ele' 

# the magic here 

>>> print new_email 
['cats', 'dogs'] 

NOTES

  • Sans mise en forme parfaite de l'e-mail, il est assez cohérent donc il y a une chance mince, un start/stop phrase se produira plus d'une fois.
  • Il n'y a pas non plus d'éléments vides.

SOLUTION

Juste pour funzies et grâce à l'aide de tout le monde ici est mon code final:

def get_elements_positions(stringList=list(), startPhrase=None, stopPhrase=None): 
    elementPositionStart, elementPositionStop = 0, -1 
    if startPhrase: 
     elementPositionStart = next((i for i, j in enumerate(stringList) if j.startswith(startPhrase)), 0) 
    if stopPhrase: 
     elementPositionStop = next((i for i, j in enumerate(stringList) if j.startswith(stopPhrase)), -1) 
    if elementPositionStart + 1 == elementPositionStop - 1: 
     return elementPositionStart + 1 
    else: 
     return [elementPositionStart, elementPositionStop] 

Il retourne une liste avec la position de l'élément de départ et de fin et par défaut à 0 et -1 si la valeur correspondante ne peut pas être trouvée. (0 étant le premier élément et -1 étant le dernier).

SOLUTION-B

J'ai fait un petit changement, maintenant si la liste est décrit un début et la position d'arrêt résultant en 1 élément entre elle retourne que les éléments la position comme un entier au lieu d'une liste que vous toujours obtenir des retours multi-ligne.

Merci encore!

+0

vous n'avez pas besoin de retourner la liste, retourner tuple fonctionne généralement très bien. [Avoir 'list()' comme valeur par défaut fait quelque chose de complètement différent.] (Http://docs.python.org/tutorial/controlflow.html#default-argument-values). La raison pour laquelle mon code est tel quel est DRY. – SilentGhost

+0

Oui, je travaille toujours sur l'ensemble de la chose "bon programmeur python". J'ai commencé à apprendre Python en conjonction avec Django, donc je pense que j'ai probablement manqué beaucoup de petites fonctionnalités de Python mais je suis en train d'apprendre. – TheLizardKing

Répondre

5
>>> email = ['apples','bananas','cats','dogs','elephants','fish','gee'] 
>>> start, stop = 'ban', 'ele' 
>>> ind_s = next(i for i, j in enumerate(email) if j.startswith(start)) 
>>> ind_e = next(i for i, j in enumerate(email) if j.startswith(stop) and i > ind_s) 
>>> email[ind_s+1:ind_e] 
['cats', 'dogs'] 

Pour satisfaire les conditions lorsque l'élément peut-être pas dans la liste:

>>> def get_ind(prefix, prev=-1): 
    it = (i for i, j in enumerate(email) if i > prev and j.startswith(prefix)) 
    return next(it, None) 


>>> start = get_ind('ban') 
>>> start = -1 if start is None else start 
>>> stop = get_ind('ele', start) 
>>> email[start+1:stop] 
['cats', 'dogs'] 
+0

Cela ne fonctionnera que s'il n'y a pas d'occurrence de la phrase d'arrêt avant la phrase de début. Ne devrait pas être trop difficile à contourner, mais gardez cela à l'esprit. –

+0

@ a-levy: fixe. – SilentGhost

+0

Est-ce que cela fonctionnera si une ou les deux phrases ne sont pas présentes dans le tableau? –

4

Une approche basée itertools:

import itertools 
email = ['apples','bananas','cats','dogs','elephants','fish','gee'] 
start, stop = 'ban', 'ele' 
findstart = itertools.dropwhile(lambda item: not item.startswith(start), email) 
findstop = itertools.takewhile(lambda item: not item.startswith(stop), findstart) 
print list(findstop)[1:] 
// ['cats', 'dogs'] 
+0

Points pour jouer – TheLizardKing

2

Ici, vous allez:

>>> email = ['apples','bananas','cats','dogs','elephants','fish','gee'] 
>>> start = 'ban' 
>>> stop = 'ele' 
>>> out = [] 
>>> appending = False 
>>> for item in email: 
...  if appending: 
...   if stop in item: 
...    out.append(item) 
...    break 
...   else: 
...    out.append(item) 
...  elif start in item: 
...   out.append(item) 
...   appending = True 
... 
>>> out.pop(0) 
'bananas' 
>>> out.pop() 
'elephants' 
>>> print out 
['cats', 'dogs'] 

I pense que ma version est beaucoup plus lisible que les autres réponses et ne nécessite aucune importation =)

+0

Votre version est plus lisible si vous vous attendez à voir chaque petit pas dans le processus. Les autres versions sont écrites dans un style de programmation plus fonctionnel. Au lieu de spécifier l'algorithme en petites étapes, ils composent l'algorithme entier en reliant des algorithmes généraux plus petits ensemble. Cela peut être déroutant au début, mais quand on s'y habitue, c'est très lisible! La solution "itertools" utilise les algorithmes "dropwhile" et "takewhile" pour résoudre le problème en 2 lignes. Une fois que vous commencez à penser fonctionnellement, vous pouvez lire et comprendre l'implémentation d'un algorithme beaucoup plus rapidement. –

+0

Cela n'a rien à voir avec "confus"; aucun des exemples ne prête à confusion. Cela a à voir avec "Explicite vaut mieux qu'implicite" et "Clairsemée vaut mieux que dense". –

Questions connexes