2016-06-09 4 views
0

In Python 2.7 möchte ich die Ähnlichkeit zwischen einer Zeichenfolge und Strings in einer Liste überprüfen, bis eine Übereinstimmung gefunden wird."TypeError: Bool ist nicht iterierbar" in jeder() Iteration mit booleschen Kriterien

from difflib import SequenceMatcher 

def similar(a, b): 
    return SequenceMatcher(None, a, b).ratio() 

correctList = ["thanks", "believe", "definitely"] 

myString = "thansk" 

for correctWord in correctList: 
    ratio = similar(correctWord, myString) 
    if ratio > 0.9: 
     myString = correctWord 
     break 

print myString 
>>> "thanks" 

Ich mag die for Iteration in weniger Zeilen vereinfachen, um so etwas wie:

if similar(myString, any([correctWord for correctWord in correctList])) > 0.9: 
    myString = correctWord 

ich über die richtige Logik hier nicht ganz sicher bin, aber in jedem Fall Varianten dieser Syntax führt den Fehler:

TypeError: ("'bool' object is not iterable", u'occurred at index 0')

Was den richtigen Weg, dies zu erreichen wäre?

+0

'any' die boolean-ness jedes Element einer Sequenz überprüft und gibt True zurück, wenn einer wurde dann Wahr und Falsch angesehen, wenn sie alle falsch sind, was Sie versuchen zu Benutze es stattdessen für? –

Antwort

2

Sie stoppen, sobald Sie die erste Zeichenfolge mit einer Ähnlichkeit> 0,9 finden, beginnend mit "thansk" als Kandidat.Deshalb denke ich, dies entspricht:

myString = "thansk" 

myString = next((w for w in correctList if similar(w, myString) > 0.9), myString) 
+0

Wenn keiner der Fälle funktioniert, wird nicht standardmäßig auf "thansk" gesetzt, es wird eine StopIteration ausgelöst. –

+0

@ TadhgMcDonald-Jensen Wenn Sie einen Standardwert wie 'None' angeben, wenn Sie' next' aufrufen, vermeiden Sie das Problem – oldrinb

+0

, um einen Fallback anzugeben, den Sie als zweites Argument an 'next' übergeben müssen, in diesem Fall wäre es '" thansk "' –

2

any sollte nur eine Liste von Booleschen Ausdrücken nehmen, so müssen wir die Bewertung similar zwischen myString und jedes Element von correctList zuerst einen Weg finden. Wir können map hier neben einem Prädikat verwenden lambda s: similar(myString, s) > 0.9:

any(map(lambda s: similar(s, myString) > 0.9, correctList)) 

Dies zu True auswertet, wenn mindestens ein Element der correctList ‚ähnlich genug‘ zu myString ist.


... aber Sie werden feststellen, dass wir die Elemente correctList sind ähnlich myString, um zu bestimmen, wollen so vielleicht sollten wir wirklich filter werden:

candidates = filter(lambda s: similar(s, myString) > 0.9, correctList) 

Sie konnte nehmen Sie einfach das erste Ergebnis, in diesem Fall die next Ausdruck würde funktionieren, aber es wäre nicht unbedingt die am ähnlichsten Element von correctList.


Wir können jedoch verwenden map, filter und max das zu erreichen. Betrachten:

pairs = map(lambda s: (s, similar(s, myString)), correctList) 

gibt eine Liste von Paaren, die jeweils aus einem Element der correctList und seine ‚Ähnlichkeitsgrad‘ mit myString. Wir können dann die Kandidaten mit Ähnlichkeit unter 0.9 herauszufiltern:

pairs = filter(lambda (s, d): d > 0.9, pairs) 

und schließlich wählen wir den Kandidaten mit maximaler Ähnlichkeit von den übrigen (mit operator.itemgetter als unsere Schlüsselfunktion) oder myString wenn keine vorhanden ist:

myString = (max(pairs, key = itemgetter(1)) or [myString])[0] 

natürlich könnten wir verwenden max auch ohne Vorfilterung und dann die Antwort außer Acht lassen, wenn die Ähnlichkeit nicht ausreicht:

pairs = map(lambda s: (s, similar(s, myString)), correctList) 
candidate = max(pairs, key = itemgetter(1)) 
myString = candidate[0] if candidate[1] > 0.9 else myString 
+1

Filter wird eine Liste oder Iterator aller Fälle, die funktionierten, nicht die erste zurückgeben. Wenn Sie Python 3 verwenden, können Sie einfach 'next()' auf das Ergebnis des Filters mit dem Standard angegeben richtig, aber es gibt keine einfache Arbeit für Python 2. –

+1

@ TadhgMcDonald-Jensen natürlich, deshalb habe ich * which * und verwendete die Pluralform von * candidate *; Wir können jedoch das eingebaute 'next' in Python 2.6+ benutzen, um den * ersten * solchen Kandidaten zu bestimmen: ' next ((s für s in correctList wenn ähnlich (s, myString)> 0.9), myString) ' – oldrinb

+0

@ TadhgMcDonald-Jensen der Grund, warum ich nicht vorschlage, ist einfach, dass der ähnlichste Kandidat nicht der erste in unserer Liste sein könnte, da wir die Ergebnisse nicht nach Ähnlichkeit ordnen – oldrinb

Verwandte Themen