2016-12-02 1 views
1

Angenommen, ich eine Liste habenWie "versteckt" man ein Element in einer Liste, wenn man die Liste an eine Funktion in Python übergibt?

myList = [a,b,c,d,e] 

und eine Funktion

def doSomething(list): 
    #Does something to the list 

Und ich möchte, wie dies die Funktion iterativ nennen:

doSomething([b,c,d,e]) 
doSomething([a,c,d,e]) 
doSomething([a,b,d,e]) 
doSomething([a,b,c,e]) 
doSomething([a,b,c,d]) 

Das erste, was würde den Sinn kommt, sei etwas wie dieses:

for x in range(0,len(myList)): 
    del myList[x] 
    doSomething(myList) 

Aber das funktioniert nicht wirklich, denn jedes Mal, wenn ich anrufe del löscht es tatsächlich das Element. Ich möchte das Element einfach jedes Mal "verstecken", wenn ich die Funktion aufruft. Gibt es eine Möglichkeit, dies zu tun?

+0

Kopieren Sie die Liste, und löschen Sie daraus? –

+0

@AndrasDeak Ich dachte, das könnte ein Weg sein, aber dann für große Listen Ich kopiere die Liste wie jedes Mal, wenn ich die Funktion anrufe, dauert das nicht viel Zeit? Wie kann ich Listen erneut kopieren? –

+0

Nun, für große Listen, ja, könnte es ineffizient sein. Das Kopieren einfacher (nicht verschachtelter) Listen ist so einfach wie 'cpy = myList [:]'. Sie können den Element-Index "k" ignorieren, indem Sie "myList [: k] + myList [k + 1:]' auf Eckfälle achten; aber dies wird auch eine Liste für Sie erstellen. –

Antwort

1

Normalerweise ist das Schleifen von Indizes eine schlechte Idee - aber in diesem Fall scheint es so, als ob Sie Elemente bei einem bestimmten Index (iterativ) entfernen wollen, so dass das Durchlaufen von Indizes tatsächlich einmalig erscheint.

Sie könnten list.pop für diesen Zweck verwenden, aber es stellt sich heraus, dass wäre eine zusätzliche O (N) -Operation für jede Runde der Schleife (einmal die Liste zu kopieren, einmal das i-te Element zu entfernen). Wir können es anders machen, indem das Element zu entfernen, während wir zu kopieren ...

for i in range(len(lst)): 
    new_list = [x for j, x in enumerate(lst) if j != i] 
    doSomething(new_list) 

ist jedoch zu beachten, dass es nicht, dass dies schneller sein wird, gewährleistet ist als der naive Ansatz:

for i in range(len(lst)): 
    new_list = lst[:] # lst.copy() in python3.x 
    new_list.pop(i) 
    doSomething(new_list) 

Des Naive Ansatz hat den Vorteil, dass die Indizierung, die in .pop getan werden muss, auf C Code geschoben wird, der im Allgemeinen schneller ist als Python-Vergleiche.

2

Sie können itertools.combinations für diesen Einsatz:

import itertools 

for sublist in itertools.combinations([a, b, c, d, e], 4): 
    # 4 is the number of elements in each sublist. 
    # If you do not know the length of the input list, use len() - 1 
    doSomething(sublist) 

Dieses sublist ein Tupel machen. Wenn Sie eine Liste benötigen, können Sie sie unter list() anrufen, bevor Sie sie an doSomething() übergeben.

Wenn Sie über die Reihenfolge egal, in denen die doSomething() Anrufe fertig sind, werden Sie wollen, um die Reihenfolge der Iteration umkehren, so dass es beginnt mit dem ersten Element anstelle des letzten Elements zu entfernen:

for sublist in reversed(list(itertools.combinations([a, b, c, d, e], 4))): 
    doSomething(sublist) 

Diese ist weniger effizient, da alle Unterlisten im Voraus und nicht einzeln nacheinander generiert werden müssen. mgilson in den Kommentaren schlägt vor, die Eingabeliste umzukehren und dann jede Teilliste umzukehren, was effizienter sein sollte, aber der Code könnte schwerer zu lesen sein.

+0

Ich dachte darüber nach, dies auch vorzuschlagen. Ich wäre interessiert zu wissen, wie Timings zwischen diesen und den naiven Ansätzen vergleichen. – mgilson

+1

Ich frage mich, ob die Reihenfolge der Funktionsausführung wichtig ist –

+1

Könnten Sie die Eingabe umkehren ('[e, d, c, b, a]') und dann die Unterlisten umkehren, bevor Sie sie an 'doSomething' übergeben? Das würde verhindern, dass _all_ die Listen im Vordergrund stehen. – mgilson

Verwandte Themen