2015-06-29 10 views
16

Angesichts der folgende Liste:Swapping zwei Teil-Listen in einer Liste

my_list=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] 

Ich mag die Unterliste tauschen können my_list[2:4] mit der Unterliste my_list[7:10] so schnell und so effizient wie möglich zu bekommen, das neue Liste:

new_list=[0, 1, 7, 8, 9, 4, 5, 6, 2, 3, 10, 11, 12] 

Hier ist mein Versuch:

def swap(s1, s2, l): 

    seg1=l[:s1.start]+l[s2] 
    seg2=l[s1.stop : s2.start] 
    seg3=l[s1]+l[s2.stop:] 

    return seg1+seg2+seg3 


print swap(slice(2,4), slice(7,10), [0,1,2,3,4,5,6,7,8,9,10,11,12]) 

das die de druckt sierte Ausgabe, obwohl diese Art, es zu tun, für mich schrecklich aussieht.

Gibt es einen einfacheren und eleganteren Weg, um für jeden Funktionsaufruf vier neue Listen zu erstellen? (Ich plane, diese Funktion viel zu nennen)

Es macht mir nichts aus (eigentlich würde ich bevorzugen), die ursprüngliche Liste zu ändern, anstatt neue Instanz jeden Funktionsaufruf zu erstellen.

+2

Was ist mit 'my_list [2: 4] = meine_liste [7:10]'? – Moritz

+2

Dies überschreibt 'my_list [2: 4]'. –

+0

Ich verstehe es nicht, weil es erzeugt: '[0, 1, 7, 8, 9, 4, 5, 6, 7, 8, 9, 10, 11, 12]' – Moritz

Antwort

25

Slices können zugewiesen werden.

Zwei Variablen können mit a, b = b, a getauscht werden.

Kombinieren Sie die beiden oben ::

>>> my_list[7:10], my_list[2:4] = my_list[2:4], my_list[7:10] 
>>> my_list 
[0, 1, 7, 8, 9, 4, 5, 6, 2, 3, 10, 11, 12] 

dass Vorsicht - wenn Scheiben unterschiedliche Größen haben - die Reihenfolge ist wichtig: Wenn Sie in der umgekehrten Reihenfolge tauschen, können Sie mit einem Ende anderes Ergebnis, weil es zuerst die Anfangselemente (niedrigere Indizes) und dann die Elemente mit höherem Index ändert (aber diese werden an einer anderen Position durch die erste Zuweisung verschoben).

Außerdem dürfen sich die Scheiben nicht überlappen.

+0

Großartig. Dies sieht viel besser und einfacher aus, und es ändert auch das Original - was vorzuziehen ist. Vielen Dank. –

+3

Ja, Sie können die Liste nicht in umgekehrter Reihenfolge austauschen. Wenn wir eine Funktion verwenden, können wir zuerst die Grenze der beiden Bereiche beurteilen. – Will

+1

Ein Eckfall, der damit versagt, sind überlappende Bereiche ... aber ich bin mir nicht sicher, ob sie auf jeden Fall ein aussagekräftiges Ergebnis liefern ... – Bakuriu

0

Ich denke, es ist viel besser, Listenindex als Parameter zu verwenden.

Wenn Sie möchten, dass Ihre fuction wie diese ersetzen neu zu definieren:

my_list=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] 

def slice_replace(src_list, l_start, l_end, r_start, r_end): 
    if l_end <= r_start: 
     return src_list[:l_start] + src_list[r_start:r_end] + src_list[l_end:r_start] + src_list[l_start:l_end] + src_list[r_end:] 
    else: 
     return slice_replace(src_list, r_start, r_end, l_start, l_end) 

print my_list 
new_list = slice_replace(my_list, 2, 4, 7, 10) 
print new_list 

new_list = slice_replace(my_list, 7, 10, 2, 4) 
print new_list 

Ich habe es behoben.

+1

Dies kann möglicherweise nicht richtig funktionieren. Es führt nur drei Slices aus, aber es gibt 5 Segmente, die insgesamt kombiniert werden müssen (die zwei gegebenen Slices und die Teile der Liste vor/zwischen/nach ihnen). – interjay

+0

@interjay Warum 5 Segmente? Ich fürchte, ich habe den Punkt nicht gesehen. – Will

+0

Versuchen Sie, Ihren Code auszuführen und zu prüfen, ob er das gewünschte Ergebnis liefert. – interjay

1

Ich denke, es ist am besten, Verkettung und Slicing zu verwenden. Wenn Sie die Liste und dann zwei Listen mit Indexpaaren übergeben, können Sie die Liste einfach trennen und die beiden Unterlisten neu anordnen. Beachten Sie, dass indexA und indexB beide in gewisser Weise als normales Slicing funktionieren, die Startnummer ist enthalten, aber das Ende ist nicht.

def replace(source, indexA, indexB): 
    newList = source[:indexA[0]] + source[indexB[0]:indexB[1]] 
    newList += source[indexA[1]:indexB[0]] + source[indexA[0]:indexA[1]] 
    newList += source[indexB[1]:] 
    return newList 

myList = replace(myList, [2,4], [7,10]) 
5

können Sie normale Swapping Technik verwenden (x,y = y,x) hier, aber nur, wenn Sie die Swap in der richtigen Reihenfolge durchführen: x muss das zweite (ganz rechts) in Scheiben schneiden, während y die ersten (ganz links) Scheibe ist.

>>> my_list=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] 
>>> my_list[7:10], my_list[2:4] = my_list[2:4], my_list[7:10] 
>>> my_list 
[0, 1, 7, 8, 9, 4, 5, 6, 2, 3, 10, 11, 12] 

Dies funktioniert, weil es zuerst my_list[7:10] vergeben wird, und erst dann zu my_list[2:4].

Wenn Sie dies in der umgekehrten Reihenfolge ausführen, wird die Zuordnung zu my_list[2:4] zuerst die Position der Elemente auf der rechten Seite ändern, da die Unterlisten unterschiedliche Längen haben, was zu falschen Ergebnissen führt.

Leistungsmäßig kann dies schneller als Ihr Code sein: es hängt wahrscheinlich von der Länge der Liste und der Slices ab. Sie müssen es an typischen Anwendungsfällen testen, um zu sehen.

1

Dies ist eine andere Art und Weise, es zu tun:

import itertools 
my_list=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] 
my_list2 = [] 
my_list2.extend((my_list[0:2],my_list[7:10],my_list[4:7],my_list[2:4],my_list[10:])) 
new_list = list(itertools.chain.from_iterable(my_list2) 

new_list Druckausgabe:

[0, 1, 7, 8, 9, 4, 5, 6, 2, 3, 10, 11, 12] 
2

Nicht ganz offensichtlich (oder effizient), aber es funktioniert. Ich war neugierig zu sehen, ob das Scheibenobjekt weiter verwendet werden könnte.

import itertools 

def replace(s1, s2, l): 
    lslice = [slice(0,s1.start), s2, slice(s1.stop, s2.start), s1, slice(s2.stop,len(l))] 
    return list(itertools.chain.from_iterable([l[x] for x in lslice]))