2016-10-02 6 views
2

Ich bin in einem Online-Kurs bei edx Python und ich muss dieses kleine Programm tun, ich denke, dass die Funktion richtig ist, aber es hat den Fehler, wenn ein Element aus der Liste plötzlich gelöscht wird nächstes Element wird nicht in den Test einbezogen.Seltsames Verhalten der Python-Funktion

def f(i): 
     return i + 2 
    def g(i): 
     return i > 5 


    def applyF_filterG(L, f, g): 
     """ 
     Assumes L is a list of integers 
     Assume functions f and g are defined for you. 
     f takes in an integer, applies a function, returns another integer 
     g takes in an integer, applies a Boolean function, 
     returns either True or False 
     Mutates L such that, for each element i originally in L, L contains 
      i if g(f(i)) returns True, and no other elements 
     Returns the largest element in the mutated L or -1 if the list is empty 
     """ 
     # Your code here 
     i = 0 
     if len(L) == 0: 
      return -1 
     while i < len(L): 
      if not g(f(L[i])): 
       del L[i] 
      i += 1 
     return max(L) 

Wenn ich mit diesem Beispiel L versuchen = [0, -10, 5, 6, -4, -2], sollte der Wert von L L = [5,6], aber das Ergebnis ist diese [-10, 5, 6, -2] das Element -10 wird übersprungen, wenn die 0 gelöscht wurde und dasselbe passiert mit -4 und -2. Bitte helfen Sie mir, ich weiß nicht, wie das gelöst werden kann.

+2

Lange Rede kurzer Sinn: Sie wollen nie eine Liste mutieren, während Sie darüber iterieren. – elethan

+2

Wenn Sie Elemente während der Iteration über eine Liste löschen möchten (obwohl dies in der Regel keine gute Idee ist), ist der beste Weg, mit dem größten Index zu beginnen und mit dem kleinsten zu arbeiten. Wenn ein Element gelöscht wird, ändert seine Löschung keine der Indizes der Elemente, die Sie noch besuchen müssen. –

Antwort

3

Versuchen Sie, nicht durch die Liste zu durchlaufen, die Sie innerhalb der Schleife in Python mutieren. In diesem Beispiel wurde die Indexreihenfolge nach dem Löschen des Elements geändert. Ich habe eine Kopie von L erstellt, bevor ich es wiederholt habe, und es macht den Trick.

def applyF_filterG(L, f, g): 
    copied_L = L[:] 
    for i in copied_L: 
     if not g(f(i)): 
      L.remove(i) 
    if len(L)==0: 
     return -1 
    else: 
     return max(L) 
+0

Dieser Code funktioniert auf jeden Fall, danke. Ich bemerkte jetzt, was mein Fehler war. – DiegoLl0895

2

Das Mutieren einer Liste während des Iterierens ist eine schlechte Idee und führt zu unerwartetem Verhalten. Im Allgemeinen erstellen Sie am besten eine neue Liste, an der Sie arbeiten können.

In diesem speziellen Fall kann Ihr Code mit einer einfachen Änderung behoben werden. Iterieren Sie den Index nur dann, wenn Sie kein Element löschen, um nicht in der Liste zu springen.

while i < len(L): 
    if not g(f(L[i])): 
     del L[i] 
    else: 
     i += 1 
+0

Es löst mein Problem, vielen Dank. Ich bemerkte jetzt, was mein Problem war. – DiegoLl0895

3

Das Problem:

Sie Löschen von Elementen aus der Liste, wie Sie über die Liste iterieren. Aus diesem Grund verweist i nicht mehr auf das richtige Element in der Liste.

Um dieses Problem zu veranschaulichen, hier ist ein Beispiel, durchlaufen Sie Ihren Code.
In diesem Beispiel gehen wir davon aus, dass die if-Anweisung ein Element löscht, wenn sein Wert gerade ist.
Ich nehme auch an, dass i bereits initialisiert wurde.

L = [1, 2, 6, 3, 4]

Iteration 1

i == 0, L [i] == 1, wir nicht löschen, das Element .
L == [1, 2, 6, 3, 4]

Iteration 2

i == 1, L [i] == 2, Element gelöscht.
L == [1, 6, 3, 4]

Iteration 3

i == 2, L [i] == 3, wir das Element nicht löschen.
L == [1, 6, 3, 4]
# Haben Sie bemerkt, dass wir die 6 einfach übersprungen haben, weil sich der Index bewegt hat ?!

Iteration 4

i == 3, L [i] == 4, Element gelöscht.
L == [1, 6, 3]

Wir sind fertig!


Es gibt ein paar Möglichkeiten, dies zu tun. Obwohl @Meerness bereits einen Weg geliefert hat, dies zu tun, hier ist ein anderer Weg, wie Sie es nur der Vollständigkeit halber tun können.

i = len(L) - 1 
if i == -1: 
    return -1 

while i >= 0: 
    if not g(f(L[i])): 
     del L[i] 
    i -= 1 

Wie das funktioniert:

Auf diese Art und Weise tun, zählen Sie nach unten aus dem obersten Index. Auf diese Weise wirkt sich das Löschen eines Elements nicht auf die Indizes von Elementen aus, die Sie noch nicht überprüft haben.
Meine Erklärung dieser Vorgehensweise ist eine leicht umformulierte Version des Kommentars von @JohnColeman.
JSYK, obwohl ich diese Lösung bereits geschrieben hatte, bevor ich seinen Kommentar sah, so entlehnte ich ihm die Idee nicht - ich entlehnte seine Erklärung nur. :)

Hier ist ein Beispiel dafür, was passiert, wenn wir statt Zählen Countdown:

L = [1, 2, 6, 3, 4]

Iteration 1

i == 4, L [i] == 4, Element wird gelöscht.
L == [1, 2, 6, 3]

Iteration 2

i == 3, L [i] == 3, wir das Element nicht gelöscht werden.
L == [1, 2, 6, 3]

Iteration 3

i == 2, L [i] == 6, Element gelöscht.
L == [1, 2, 3]

Iteration 4

i == 1, L [i] == 2, Element gelöscht.
L == [1, 3]

Iteration 5

i == 0, L [i] == 1, wir haben das Element nicht gelöscht werden.
L == [1, 3]

Wir sind fertig!


PS: Beispiele automatisch mit python3 Skript generiert. :)

0
def applyF_filterG(L, f, g): 
    """ 
    Assumes L is a list of integers 
    Assume functions f and g are defined for you. 
    f takes in an integer, applies a function, returns another integer 
    g takes in an integer, applies a Boolean function, 
     returns either True or False 
    Mutates L such that, for each element i originally in L, L contains 
     i if g(f(i)) returns True, and no other elements 
    Returns the largest element in the mutated L or -1 if the list is empty 
    """ 

    M =[] 
    for i in range(len(L)): 
     if g(f(L[i])): 
      M.append(L[i]) 
    L = M[:] 
    if len(L)==0: 
     return -1 
    else: 
     return max(L)