2012-03-23 10 views
7

Ich versuche, Elemente aus einer verschachtelten Liste in Python zu entfernen. Ich habe eine verschachtelte Liste wie folgt:Entfernen von Elementen aus einer verschachtelten Liste Python

families = [[0, 1, 2],[0, 1, 2, 3],[0, 1, 2, 3, 4],[1, 2, 3, 4, 5],[2, 3, 4, 5, 6]] 

ich die Einträge in jeder Unterliste entfernen möchten, die auf die indexierte Position des sublist in der Masterliste coorespond. Also zum Beispiel, ich muss 0 aus der ersten Unterliste entfernen, 1 aus der zweiten Unterliste, etc. Ich versuche, eine Listenbefugnis zu verwenden, dies zu tun. Dies ist, was ich versucht habe:

familiesNew = [ [ families[i][j] for j in families[i] if i !=j ] for i in range(len(families)) ] 

Dies funktioniert für range(len(families)) bis zu 3, aber darüber hinaus, dass ich IndexError: list index out of range bekommen. Ich bin mir nicht sicher warum. Kann mir jemand eine Idee geben, wie man das macht? Vorzugsweise ein Einzeiler (Listenverständnis).

Danke.

Antwort

9

Sie haben es fast richtig gemacht. Ersetzen Sie einfach families[i][j] mit j und es funktioniert:

>>> [ [ j for j in families[i] if i !=j ] for i in range(len(families)) ] 
[[1, 2], [0, 2, 3], [0, 1, 3, 4], [1, 2, 4, 5], [2, 3, 5, 6]] 

Es kann ein bisschen sauberer mit der enumerate Funktion geschrieben werden:

>>> [[f for f in family if f != i] for i, family in enumerate(families)] 
[[1, 2], [0, 2, 3], [0, 1, 3, 4], [1, 2, 4, 5], [2, 3, 5, 6]] 

Oder sogar remove verwenden, wenn Sie nichts dagegen haben die ursprüngliche Liste zu ändern:

>>> for i, family in enumerate(families): family.remove(i) 
+0

Danke, ich mit der letzten Option beschlossen zu gehen, wie es in der Tat in Ordnung und wünschenswert war die Liste an Ort und Stelle zu ändern. – johntfoster

3

Macht das, was Sie wollen?

familiesNew=[ filter(lambda x:x!=i,j) for i,j in enumerate(families) ] 

EDIT

Beachten Sie auch der Grund, Ihr gescheitert ist, weil auf dem dritten Element der äußeren Liste ([1, 2, 3, 4, 5]) Sie versuchen, das fünfte Element in der for-Schleife zu erhalten (for j in families[i] = = for j in [1,2,3,4,5]), aber Familien [i] hat eine Länge von 5, ist der größte Index Bedeutung 4. Sorry, wenn diese Erklärung ein wenig unklar ist ... vielleicht wird folgendes klar helfen, es auf ein wenig:

families = [[0, 1, 2],[0, 1, 2, 3],[0, 1, 2, 3, 4],[1, 2, 3, 4, 5],[2, 3, 4, 5, 6]] 

def f(i,j): 
    print i,j,families[i] 
    return families[i][j] 
#THIS DOES NOT WORK -- but it will tell you where it failed. 
familiesNew = [ [ f(i,j) for j in families[i] if i !=j ] for i in range(len(families)) ] 
5

Bearbeitete Frage, lösche meine Antwort, die das falsche Problem gelöst hat. Auch hinzugefügt zusätzliche Antwort von @Ashwini:

Zum Vergleich willen:

root# python -m timeit 'families = [[0, 1, 2],[0, 1, 2, 3],[0, 1, 2, 3, 4],[1, 2, 3, 4, 5],[2, 3, 4, 5, 6]]' '[x.remove(ind) for ind,x in enumerate(families) ]' 
100000 loops, best of 3: 3.42 usec per loop  

root# python -m timeit -s 'families = [[0, 1, 2],[0, 1, 2, 3],[0, 1, 2, 3, 4],[1, 2, 3, 4, 5],[2, 3, 4, 5, 6]]' '[[f for f in family if f != i] for i, family in enumerate(families)]' 
100000 loops, best of 3: 4.87 usec per loop 

root# python -m timeit -s 'families = [[0, 1, 2],[0, 1, 2, 3],[0, 1, 2, 3, 4],[1, 2, 3, 4, 5],[2, 3, 4, 5, 6]]' '[ filter(lambda x:x!=i,j) for i,j in enumerate(families) ]' 
100000 loops, best of 3: 7.99 usec per loop 

Dies sind Mikrosekunde, so dass ich denke, was Sie wollen tun, ist in Ordnung, wenn Sie diese ein gehen zu tun Los von Zeiten.

+0

Ich denke, die Semantik ist nicht ganz richtig. Es ist nicht so, dass das Element am * index * "i" aus jeder Unterliste entfernt werden sollte, sondern das Element "i" selbst. –

+0

Dies ist ein cleverer Trick, aber ich denke, dass es nicht ganz das tut, was es beabsichtigt ist. (Es würde funktionieren, wenn die letzten Elemente der äußeren Liste Sequenzen wären, die bei 0 beginnen). +1 für Zeit obwohl. – mgilson

+0

Mein Fehler, die Absicht der Frage falsch zu lesen (und anschließend die Ausgabe nicht zu überprüfen) – sberry

2

Wenn Sie die ursprüngliche Liste ändern wollen, dann versuchen Sie dies:

>>>[x.remove(ind) for ind,x in enumerate(families) ] 
>>>families 
[[1, 2], [0, 2, 3], [0, 1, 3, 4], [1, 2, 4, 5], [2, 3, 5, 6]] 
+0

Diese Antwort ist interessant, weil sie die Berechnung durchführt. Vermutlich würde es eine Liste von None zurückgeben ... aber das könnte für einige Anwendungen in Ordnung sein. – mgilson

+0

ja! Dieses Listenverständnis gibt eine Liste von Keine Länge == len (Familien) zurück und ändert die ursprüngliche Liste. –

+0

gute Lösung, obwohl es in der Regel unhöflich ist, ein Listenverständnis für Nebenwirkungen zu verwenden. –