2016-08-25 1 views
2

Ich mag würde eine Liste von Strings auf Substrings basierend auf Scheiben schneiden möglicherweise in seine Elemente enthalten:Slicing Liste mit verschiedenen String-Matching-Bedingungen

l = ['Some long text', 'often begins', ' with ', 
    'impenetrable fog ', 'which ends', ' somewhere further'] 
startIndex = [u for u, v in enumerate(l) if 'begins' in v)][0] 
finalIndex = [u for u, v in enumerate(l) if 'ends' in v)][0] 

so dass ich bekommen würde:

' '.join(l[startIndex:finalIndex]) == 'often begins with impenetrable fog' 

Mein Hauptproblem ist, dass die Anfangs- und Endbedingungen, die zum Abrufen von Indizes verwendet werden, unterschiedlich sind und variabel sein sollten (grundlegende Unterstreichungsbeschränkung wie oben erwähnt, Regexe oder andere Methoden möglich). Die ersten und letzten Elemente müssen möglicherweise entfernt werden, aber ich denke, dies ist eine Frage der Anpassung der Indizes um 1. Mein Code funktioniert im Idealfall, aber wird oft scheitern, da Struktur und Inhalt l nicht sehr vorhersehbar sind. Das Fehlen eines oder beider Elemente, die den Bedingungen entsprechen, sollte mit der letzten Zeichenfolge None enden.

Sind die Comprehensions relevant oder wird eine Lambda-Funktion zugeordnet, um beide Bedingungen anzuwenden?

+0

Können Sie bitte das klare Beispiel nennen? Willst du alle 'strings' in' list' zwischen den 'start' und' end' Strings.Zum Beispiel: '['How May', 'Ich helfe', 'Du mit', 'Dein Problem', 'Andreas']'. Mit start = 'help' und end =' Problem'. Was sollte Ihre benötigte Ausgabe sein? –

+0

Ja Ich möchte "Sie mit Ihrem Problem" als Ausgabe mit Ihrem Beispiel erhalten. Danke für die Antwort! –

+0

Was haben Sie übrigens schon mit Map- und Lambda-Funktionen probiert? –

Antwort

1

Versuchen:

l = ['Some long text', 'often begins', 'with', 'impenetrable fog', 'which ends', 'somewhere further'] 

""" 
return the index of the phase in 'phases' if phase contains 'word' 
if not found, return 'default' 
""" 
def index(phases, word, default): 
    for i, s in enumerate(phases): 
     if word in s: return i 
    return default 

startIndex = index(l, "long", -1) 
finalIndex = index(l, "somewhere", len(l)) 

print(' '.join(l[startIndex+1:finalIndex])) 
1

Oder mit next():

l = ['Some long text', 'often begins', ' with ', 'impenetrable fog ', 
    'which ends', ' somewhere further'] 

startIndex = next((u for u, v in enumerate(l) if 'begins' in v), 0) 
finalIndex = next((u for u, v in enumerate(l) if 'ends' in v), 0) 

if (startIndex and finalIndex) and (finalIndex > startIndex): 
    sentence = ' '.join(l[startIndex:finalIndex]) 
else: 
    sentence = None 
print(sentence) 

Ähnlich wie Liste Verständnis, execpt es gibt nicht eine Liste, aber das erste Element gefunden. wenn er nichts gefunden hat, ist es ein optionales Element zurückkehren (hier '0')

Auf diese Weise, wenn es keine 'begins' oder keine 'ends' in Ihrer Liste ist, Sie müssen nicht alles drucken. Daher können Sie entweder überprüfen, ob der 'ends' vor dem 'begins' steht.

Ich liebe auch Listenverständnis, aber manchmal, was Sie brauchen, ist keine Liste.

LÖSUNG FÜR ADVANCE USER:

Das Problem bei der Verwendung von zwei Verständnis Liste, ist, dass Sie von Anfang zweimal Ihrer Liste überprüfen und es wird fehlschlagen, wenn ends vor dem Start kommt:

l = ['Some long text ends here', 'often begins', ' with ', 'which ends'] 
        ^^^ 

Um dies zu vermeiden, können Sie einen Generator mit send() verwenden, um nur einmal auf Ihrer Liste zu iterieren.

def get_index(trigger_word): 
    for u, v in enumerate(l): 
     if trigger_word in v: 
      trigger_word = yield u 

gen = get_index('begins') 
startIndex = gen.send(None) 
finalIndex = gen.send('ends') 

Hier ist die yield ermöglicht es Ihnen, den Index zu erhalten, ohne die Funktion zu verlassen.

Das ist besser, aber wenn es keine begins oder ends in der Liste gibt, wird es eine StopIteration Ausnahme geben. Um dies zu vermeiden, können Sie stattdessen eine Endlosschleife auf yield 0 ausführen. Nun ist die Komplettlösung wird:

def get_index(l, trigger_word): 
    for u, v in enumerate(l): 
     if trigger_word in v: 
      trigger_word = yield u 
    while True: 
     yield 0 

def concat_with_trigger_words(l):   
    gen = get_index(l, 'begins') 
    startIndex = gen.send(None) 
    finalIndex = gen.send('ends') 
    return ' '.join(l[startIndex:finalIndex]) if (startIndex and finalIndex) else None 

# Here some list for free lists for your future unitary tests ;) 

l_orignal = ['Some long text here', 'often begins', ' with ', 
      'impenetrable fog ', 'which ends', ' somewhere further'] 
l_start_with_ends = ['ends', 'often begins', ' with ', 
        'impenetrable fog ', 'which ends', 'begins'] 
l_none = ['random', 'word'] 
l_without_begin = ['fog', 'ends here'] 
l_without_end = ['begins', 'but never' '...'] 

print(concat_with_trigger_words(l_orignal)) # often begins with impenetrable fog 
print(concat_with_trigger_words(l_start_with_ends)) # often begins with impenetrable fog 
print(concat_with_trigger_words(l_none)) # None 
print(concat_with_trigger_words(l_without_end)) # None 
print(concat_with_trigger_words(l_without_begin)) # None 
1
>>> l = ['Some long text', 'often begins', ' with ', 
...  'impenetrable fog ', 'which ends', ' somewhere further'] 
>>> start, end = 'begins', 'ends' 
>>> key_index = {'start': {'word': start, 'index': -1}, 
       'end': {'word': end, 'index': -1}} 
>>> for i, val in enumerate(l): 
...  if key_index['start']['word'] in val: 
...   key_index['start']['index'] = i 
...  elif key_index['end']['word'] in val: 
...   key_index['end']['index'] = i 
... 
>>> start_index, end_index = key_index['start']['index'], key_index['end']['index'] 
>>> my_list = l[start_index+1:end_index] if start_index >=0 and end_index >= 0 and start_index+1 < end_index else None 
>>> my_list 
[' with ', 'impenetrable fog ']