2011-01-12 10 views
2

ich vor kurzem eine Methode, um durch /usr/share/dict/words und eine Liste von Palindrome mit meiner ispalindrome(x) Methode einige des Code hier geschrieben ... was ist los mit ihm? es Stände nur 10 Minuten und gibt dann eine Liste aller Wörter in der DateiPython und Palindrome

 
def reverse(a): 
    return a[::-1] 

def ispalindrome(a): 
    b = reverse(a) 
    if b.lower() == a.lower(): 
     return True 
    else: 
     return False 

wl = open('/usr/share/dict/words', 'r') 
wordlist = wl.readlines() 
wl.close() 
for x in wordlist: 
    if not ispalindrome(x): 
     wordlist.remove(x) 
print wordlist 
+2

Eine kürzere Inline-Definition von 'ispalindrome = Lambda a: a [:: - 1] .lower() == a.lower()' spart Ihnen weitere ~ 25% der Zeit. – eumiro

+4

Nicht verwandt mit Ihrem Problem, aber Ihre zweite Funktion kann auf 'return (reverse (a) .lower() == a.lower())' reduziert werden. Das '==' gibt bereits 'True' oder' False' zurück, so dass es nicht nötig ist, eine 'if' Anweisung darum zu legen. –

Antwort

5
wordlist = wl.readlines() 

Wenn Sie dies tun, gibt es eine neue Zeile Zeichen am Ende, so dass Ihre Liste ist wie:

['eye\n','bye\n', 'cyc\n'] 

deren Elemente sind offensichtlich nicht ein Palindrom.

Sie müssen dies:

['eye','bye', 'cyc'] 

strip Also das Newline-Zeichen und es sollte in Ordnung sein.

dies in einer Zeile zu tun:

wordlist = [line.strip() for line in open('/usr/share/dict/words')] 

EDIT: Iterieren über eine Liste und Modifizieren es verursacht Probleme. Verwenden Sie ein Listenverständnis, wie in Matthew angegeben.

1

Du einschließlich des Newline am Ende jedes Wortes in /usr/share/dict/words. Das bedeutet, dass Sie niemals Palindrome finden. Du wirst die Dinge beschleunigen, wenn du die Palindrome einfach so aufspürst, wie du sie findest, anstatt auch Nicht-Palindrome aus der Liste zu löschen.

+0

Das stimmt, aber es erklärt nicht, warum es etwas druckt. –

+0

@Johns, lesen Sie den ursprünglichen Code. Es versucht, * non * -Pallindrome zu entfernen. Und es entfernt die Hälfte. Es kann nicht alle aufgrund von Änderungen während der Iteration entfernt werden. –

+0

Sie haben natürlich Recht. Ich habe meine Antwort entsprechend aktualisiert. – Johnsyweb

3

Ich denke, es gibt zwei Probleme.

Erstens, was ist der Sinn beim Lesen aller Wörter in einer Liste? Warum nicht jedes Wort nacheinander verarbeiten und es ausdrucken, wenn es ein Palindrom ist.

Zweitens, aufpassen whitespace. Sie haben neue Zeilen am Ende jedes Ihrer word s!

Da Sie keine Palindrome (aufgrund des Leerraums) identifizieren, werden Sie versuchen, alle Elemente aus der Liste zu entfernen. Während du darüber iterierst!

Diese Lösung läuft in gut unter einer Sekunde und zeigt viele Palindrome:

for word in open('/usr/share/dict/words', 'r'): 
    word = word.strip() 
    if ispalindrome(word): 
     print word 

bearbeiten:

Vielleicht mehr 'pythonic' ist generator Ausdrücke zu verwenden:

def ispalindrome(a): 
    return a[::-1].lower() == a.lower() 

words = (word.strip() for word in open('/usr/share/dict/words', 'r')) 
palindromes = (word for word in words if ispalindrome(word)) 
print '\n'.join(palindromes) 
+0

Was komisch ist, ist, dass er Elemente aus der Liste entfernt, wenn sie * kein * Palindrom sind, also sollte er jeden einzelnen Eintrag entfernen. –

+0

@Tim: Aha ... Ja. Du hast recht. Dies wird versuchen, * alles * aus der Liste zu entfernen, aber wie es iteriert. Böse! – Johnsyweb

2

Es gibt nicht alle Wörter zurück. Es gibt die Hälfte zurück. Dies liegt daran, dass Sie die Liste ändern, während Sie darüber iterieren, was ein Fehler ist. Eine einfachere und effektivere Lösung ist die Verwendung eines Listenverständnisses. Sie können Sukhbir das ändern, die ganze Sache zu tun:

[word for word in (word.strip() for word in wl.readlines()) if ispalindrome(word)] 

Sie können dies auch brechen:

stripped = (word.strip() for word in wl.readlines()) 
wordlist = [word for word in stripped if ispalindrome(word)] 
3

Andere haben schon bessere Lösungen aufgezeigt.Ich möchte Ihnen zeigen, warum die Liste nicht leer ist, nachdem Sie Ihren Code ausgeführt haben. Da Ihre ispalindrome() Funktion nie True wegen des "newlines Problem" zurückgibt, das in den anderen Antworten erwähnt wird, ruft Ihr Code wordlist.remove(x) für jedes einzelne Element auf. Warum ist die Liste am Ende nicht leer?

Weil Sie die Liste ändern, während Sie darüber iterieren. Beachten Sie Folgendes:

>>> l = [1,2,3,4,5,6] 
>>> for i in l: 
...  l.remove(i) 
... 
>>> l 
[2, 4, 6] 

Wenn Sie die 1 entfernen, wird der Rest der Elemente nach oben einen Schritt bewegt, so dass nun l[0]2 ist. Der Iterationszähler ist jedoch fortgeschritten und wird in der nächsten Iteration l[1] betrachten und daher 3 und so weiter entfernen.

Ihr Code entfernt also die Hälfte der Einträge. Moral: Ändern Sie niemals eine Liste, während Sie darüber iterieren (es sei denn, Sie wissen genau, was Sie tun :)).