2017-12-08 4 views
0

Also habe ich 2 Klassen namens Einladung und Antwort erstellt. Dann habe ich eine Klasse namens Event erstellt. Innerhalb der Event-Klasse muss ich eine Funktion erstellen, die die aktuelle Liste der Einladungen und die Liste der Antworten anzeigt und zählt, wie viele Einladungen keine Antwort haben.Warum wird diese Instanz nicht aus meiner Objektliste entfernt?

Die Einladungen und die Antworten haben beide ein Attribut "name", das ich in meiner Methode get_pending() verwende.

Ich habe eine Instanz der Klasse "E" bezeichnet, die wie folgt aussieht:

e = Event("graduation",[Invitation("A",5),Invitation("B",10),Invitation("C",5),Invitation("D",7)], [Response("A",True,5),Response("B",True,6),Response("C",False,0),Response("D",True,1)]) 

ich dann drucken Sie die Klassenmethode get_pending:

print(e.count_pending()) 

Hier mein Code mit dem get_pending ist() -Methode :

class Invitation: 
    def __init__(self, name, num_invited): 
     self.name = name #str 
     self.num_invited = num_invited #positive int 
    def __str__(self): 
     return ("Invitation('%s', %i)" % (self.name, self.num_invited)) 
    def __repr__(self): 
     return str(self) 
    def __eq__(self, other): 
     if self.name == other.name and self.num_invited == other.num_invited: 
      return True 
    def __lt__(self, other): 
     if self.name < other.name: 
      return True 
     elif self.name == other.name: 
      if self.num_invited < other.num_invited: 
       return True 
class Response: 
    def __init__(self, name, ans, num_attending): 
     self.name = name #str 
     self.ans = ans #bool - T/F 
     self.num_attending = num_attending #zero or more people 
    def __str__(self): 
     return ("Response('%s', %r, %i)" % (self.name, self.ans, self.num_attending)) 
    def __repr__(self): 
     return str(self) 
    def __eq__(self, other): 
     if self.name == other.name and self.ans == other.ans and self.num_attending == other.num_attending: 
      return True 
    def __lt__(self, other): 
     if self.name < other.name: 
      return True 
     elif self.name == other.name: 
      if self.ans < other.ans: 
       return True 
      elif self.ans == other.ans: 
       if self.num_attending < other.num_attending: 
        return True 
class Event: 
    def __init__(self, title, invites=None, responses=None): 
     self.title = title #str 
     self.invites = invites #list 
     self.responses = responses #list 
     if self.invites == None: 
      self.invites = [] 
     if self.responses == None: 
      self.responses = [] 
     self.invites.sort() 
     self.responses.sort() 
    def __str__(self): 
     return ("""Event('%s', %r, %r)""" % (self.title, self.invites, self.responses)) 
    def __repr__(self): 
     return str(self) 
    def __eq__(self, other): 
     if self.title == other.title and self.invites == other.invites and self.responses == other.responses: 
      return True 
    def count_pending(self): 
     num_pending = 0 
     lst_noresp = self.invites[:] 
     for invi in lst_noresp: 
      if (any(invi.name == resp.name for resp in self.responses)) == True: 
       lst_noresp.remove(invi) 
     for invi in lst_noresp: 
      num_pending += invi.num_invited 
     return num_pending 

e = Event("graduation",[Invitation("A",5),Invitation("B",10),Invitation("C",5),Invitation("D",7)], [Response("A",True,5),Response("B",True,6),Response("C",False,0),Response("D",True,1)]) 
print(e.count_pending()) 

Mein Fehler ist, dass die count_pending() Methode nur Entfernen einige (Invite mit Namen 'A' und Invite mit Namen 'C') Objekte aus der Einladungsliste, obwohl alle Einladungen eine entsprechende Antwort haben. Warum funktioniert der Vergleich invi.name == resp.name nicht ordnungsgemäß? Oder ist das überhaupt das Problem?

+0

Ein paar '' '' '' '' '' 'zum Debuggen können hilfreich sein, vor allem ein' print (invi) 'direkt vor oder nach' lst_noresp.remove (invi) ', um zu sehen, ob das' if' korrekt funktioniert. –

+0

Danke, ich werde den Code aktualisieren, um dies widerzuspiegeln und hier zurück zu posten, wenn ein Problem auftaucht. – ruckarucka

+0

@MichaelButscher So habe ich festgestellt, dass die Zeile "if (any (invi.name == resp.name für resp in self.responses)) == True:" zu einem Generator-Exit für die zweite und vierte Einladung führt, aber nicht für die erste und dritte lädt – ruckarucka

Antwort

1

Sie haben das klassische Problem der Bereitstellung eines list mutiert, während es hier Iterieren:

for invi in lst_noresp: # Iterating 
     if (any(invi.name == resp.name for resp in self.responses)) == True: 
      lst_noresp.remove(invi) # Mutating 

Zwar gibt es keine dokumentierten Verhalten für sie ist, in der Praxis ist dies bewirkt, dass die Schleife den Wert nach jedem entfernt Element überspringen (Der Iterator speichert den aktuellen Index und der remove verschiebt die folgenden Elemente nach unten. Wenn Sie also das nächste Element erhalten, haben Sie das Element umgangen, das in den vom entfernten Element belegten Platz verschoben wurde) Überprüfen Sie die Hälfte Ihrer Werte. Iterate über self.invites, und mutiere lst_noresp, und das Problem sollte verschwinden.

Alternativ bauen ein neues list und vermeiden O(n**2) Leistung:

lst_noresp = [invi for invi in self.invites 
        if not any(invi.name == resp.name for resp in self.responses)] 

die langsam Entnahmen aus der Mitte eines list zugunsten von Filtern während des Baus eines neuen list (O(n) Arbeit) vermeidet.

+0

Danke, das macht Sinn! Wäre eine andere Möglichkeit, das Problem zu lösen (an das ich eher gewöhnt bin), eher das Entfernen von Einladungen, die bereits in den Antworten vorhanden sind. Kann ich einfach alle Einladungen, die keine Antwort auf eine neue Liste haben, an diese Liste anhängen? – ruckarucka

+0

@ruckckucka: Heh. Ich habe diesen Ansatz nur hinzugefügt, als Sie kommentiert haben. Ja, es ist im Allgemeinen einfacher und effizienter, das zu tun, siehe Beispielcode. – ShadowRanger

+0

Ja, ich stimme dem völlig zu, danke für den aktualisierten Code. – ruckarucka

Verwandte Themen