Rekursion mit Liste: Error: can only concatenate list (not "NoneType") to list

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Unplayable
User
Beiträge: 51
Registriert: Mittwoch 24. Februar 2016, 22:09

Hallo Zusammen,

ich möchte ein Programm schreiben, welches eine neue Liste aus den Zahlen einer liste zurückliefert, die ohne Rest durch eine bestimmte Zahl teilbar sind. Das ist der Code:

Code: Alles auswählen

def listenfilter_teilbar(liste,zahl):
    a=[]
    if liste==[]:
        return a
    if liste[0]%zahl==0:
        a.append(liste[0])
        a = a+listenfilter_teilbar(liste[1:],zahl)
        return a
    else:
        a=a+listenfilter_teilbar(liste[1:],zahl)
beim Ausführen kommt aber jedes Mal der oben angegebene Fehlercode?
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@Unplayable: ist Deine Hausaufgabe, Rekursion zu benutzen? Denn hier ist eine rekursive Lösung deutlich komplizierter als eine nicht-rekursive.
Wenn Du eine Fehlermeldung hast, dann ist der sogenannte Traceback genauso wichtig. Dort steht nämlich, wo genau im Programmablauf der Fehler auftritt. So muß jetzt jeder, der Dir helfen will, raten, an welcher Stelle der Fehler genau auftritt.
Erst eine leere Liste zu erstellen, um dann diese leere Liste mit einer anderen Liste per + zu kombinieren, ist ziemlich umständlich.
Kommt der Programmablauf ans Ende einer Funktion, ohne return, so wird implizit None zurückgegeben.
Unplayable
User
Beiträge: 51
Registriert: Mittwoch 24. Februar 2016, 22:09

Ja ist die Aufgabe, das ganze rekursiv zu gestalten. Die Liste die übergeben wird, soll dabei nicht verändert werden, weshalb ich die Liste a erstellt habe.

Hier ist der Fehlercode in der Shell. Es muss also im Else Zweig irgendwas schief gelaufen sein?:

>>> listenfilter_teilbar([2,4,8],2)
[2, 4, 8]
>>> listenfilter_teilbar([2,4,8,15],2)
Traceback (most recent call last):
File "<pyshell#8>", line 1, in <module>
listenfilter_teilbar([2,4,8,15],2)
File "B:/Info 11 LK/AB08.py", line 21, in listenfilter_teilbar
a = a+listenfilter_teilbar(liste[1:],zahl)
File "B:/Info 11 LK/AB08.py", line 21, in listenfilter_teilbar
a = a+listenfilter_teilbar(liste[1:],zahl)
File "B:/Info 11 LK/AB08.py", line 21, in listenfilter_teilbar
a = a+listenfilter_teilbar(liste[1:],zahl)
TypeError: can only concatenate list (not "NoneType") to list
>>>
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Dass man die Liste nicht verändern soll, bedeutet noch nicht, dass man `a` so kompliziert benutzen muß. Zu Deinem Problem habe ich ja schon geantwortet.

Dann kann ich ja die nicht-rekursive Lösung posten:

Code: Alles auswählen

def listenfilter_teilbar(liste, zahl):
    return [num for num in liste if liste % zahl == 0]
Unplayable
User
Beiträge: 51
Registriert: Mittwoch 24. Februar 2016, 22:09

Ohje wie blöd von mir. So spät sollte ich wohl nicht mehr programmieren. Hab mir aber mit dem Prinzip der Rekursion etwas schwer getan. Nachdem ich return a hinzugefügt habe, läuft es. Vielen Dank :)
Unplayable
User
Beiträge: 51
Registriert: Mittwoch 24. Februar 2016, 22:09

Wie könnte man das mit a denn einfacher machen?
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@Unplayable: Du initialisiert a als leere Liste, so dass das Ergebnis jeder Operation in den if-Zweigen schon feststeht:

Code: Alles auswählen

def listenfilter_teilbar(liste, zahl):
    if not liste:
        # Liste ist leer -> Ende der Rekursion
        return []
    # Erzeuge die Ergebnisliste, je nachdem, ob das erste Element teil davon ist, oder nicht
    if liste[0]%zahl==0:
        result = [liste[0]]
    else:
        result = []
    # Füge den Rest zum Ergebnis hinzu
    result.extend(listenfilter_teilbar(liste[1:], zahl))
    return result
Diese Funktion erzeugt immer noch für jedes Element der Eingangsliste eine neue Liste (aber immerhin nicht 2 wie bei Dir) und kopiert alle Listenelemente n^2/2 mal. Filtern ist einfach kein Problem, das man rekursiv löst. Lernen an Beispielen ist zwar gut, aber an Beispielen, an denen Rekursion sinnlos ist, führt nur dazu, dass irgendjeman denken könnte, ähnliche Probleme würden auch so gelöst werden.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@Sirius3: der TE hat Dein nicht-rekursives Beispiel vermutlich nicht ausprobiert, sonst wäre ihm der Fehler in der Condition aufgefallen, die 'if not num % zahl' lauten müsste.

@Unplayable: Rekursion ist in Python zwar möglich, aber man sollte wissen, dass die damit verbundenen Funktionsaufrufe teuer sind sowie die Rekursionstiefe begrenzt ist. Wenn sich eine rekursive Lösung auch interativ formulieren lässt (und das ist praktisch immer der Fall), dann ist dieser Lösungsweg in Python oftmals die bessere Wahl.
Kniffte
User
Beiträge: 64
Registriert: Dienstag 27. September 2016, 11:05

kbr hat geschrieben:@Sirius3: der TE hat Dein nicht-rekursives Beispiel vermutlich nicht ausprobiert, sonst wäre ihm der Fehler in der Condition aufgefallen, die 'if not num % zahl' lauten müsste.

Code: Alles auswählen

if num % zahl == 0
wenn ich mich nicht irre ^^
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@Kniffte: Du irrst Dich. Ich meinte, was ich schrieb :wink:
Kniffte
User
Beiträge: 64
Registriert: Dienstag 27. September 2016, 11:05

@kbr
ahjo...jetzt hab ich´s...ich bin davon ausgegangen, dass du nur das 'liste' korrigieren wolltest und das '== 0' nur nicht geschrieben hast.
Aber so ergibt´s natürlich Sinn...sorry :?

Code: Alles auswählen

def listenfilter_teilbar(liste, zahl):
    return [num for num in liste if not num % zahl]
Unplayable
User
Beiträge: 51
Registriert: Mittwoch 24. Februar 2016, 22:09

Sirius3 hat geschrieben:@Unplayable: Du initialisiert a als leere Liste, so dass das Ergebnis jeder Operation in den if-Zweigen schon feststeht:

Code: Alles auswählen

def listenfilter_teilbar(liste, zahl):
    if not liste:
        # Liste ist leer -> Ende der Rekursion
        return []
    # Erzeuge die Ergebnisliste, je nachdem, ob das erste Element teil davon ist, oder nicht
    if liste[0]%zahl==0:
        result = [liste[0]]
    else:
        result = []
    # Füge den Rest zum Ergebnis hinzu
    result.extend(listenfilter_teilbar(liste[1:], zahl))
    return result
Diese Funktion erzeugt immer noch für jedes Element der Eingangsliste eine neue Liste (aber immerhin nicht 2 wie bei Dir) und kopiert alle Listenelemente n^2/2 mal. Filtern ist einfach kein Problem, das man rekursiv löst. Lernen an Beispielen ist zwar gut, aber an Beispielen, an denen Rekursion sinnlos ist, führt nur dazu, dass irgendjeman denken könnte, ähnliche Probleme würden auch so gelöst werden.


Leider verstehe ich Zeile 11 deines Codes überhaupt nicht :(. Ich tu mir mit der Rekursiven Funktion irgendwie total schwer. Gibt es irgendwo ein Tutorial, welches einem diese Funktion einfach erklärt? Braucht man sowas in Python oft?
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@Unplayable: was verstehst Du denn an der Zeile 11 nicht? Wie kbr schon geschrieben hat, braucht man Rekursion fast nie. Eigentlich ist da auch nicht viel dran. Rekursion heißt einfach, eine Funktion ruft sich selbst mit veränderten Parametern auf, bis eine Abbruchbedingung erfüllt wird.
Antworten