2015-06-29 18 views
16

względu na poniższej liście:Zamiana dwa listy zagnieżdżone na liście

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

Chcę, aby móc jak najszybciej i jak najefektywniej zamienić podmenu my_list[2:4] z podmenu my_list[7:10], aby uzyskać nowa lista:

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

Oto moja próba:

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]) 

ten jest drukowany DE spontaniczne wyniki, chociaż ten sposób robienia tego wygląda okropnie.

Czy jest to prostszy i bardziej elegancki sposób, który nie tworzy czterech nowych list dla każdego wywołania funkcji? (Mam zamiar nazwać tę funkcję bardzo często)

Nie mam nic przeciwko (właściwie wolałbym) zmienianie oryginalnej listy, zamiast tworzenia nowej instancji dla każdej funkcji.

+2

Co z 'my_list [2: 4] = my_list [7:10]'? – Moritz

+2

To spowoduje nadpisanie 'my_list [2: 4]'. –

+0

Nie rozumiem, ponieważ tworzy: '[0, 1, 7, 8, 9, 4, 5, 6, 7, 8, 9, 10, 11, 12]' – Moritz

Odpowiedz

25

Plasterki można przypisać.

Dwie zmienne można zamienić na a, b = b, a.

połączyć dwa powyżej ::

>>> 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] 

Pamiętaj, że - jeśli plastry mają różne rozmiary - zlecenie jest ważne: Jeśli zamienić w odwrotnej kolejności, możesz skończyć z inny wynik, ponieważ zmieni on najpierw początkowe pozycje (niższe indeksy), a następnie wyższe pozycje indeksu (ale te zostaną przesunięte w innej pozycji o pierwsze przypisanie).

Ponadto plasterki nie mogą się nakładać.

+0

Świetnie. Wygląda to znacznie lepiej i prostrze, a także zmienia oryginał - co jest lepsze. Dziękuję Ci. –

+3

Tak, nie można zamienić listy w odwrotnej kolejności. Jeśli używamy funkcji, możemy najpierw ocenić granicę dwóch zakresów. – Will

+1

Narożnikowy przypadek, który zawodzi, to nakładające się zakresy ... jednak nie jestem pewien, czy przyniosą one jakiekolwiek znaczące wyniki w każdym przypadku ... – Bakuriu

0

Myślę, że znacznie lepiej jest używać indeksu listy jako parametrów.

Jeśli chcesz przedefiniować swoją zastąpić fuction tak:

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 

mam naprawił.

+1

To prawdopodobnie nie działa poprawnie. Wykonuje tylko trzy plasterki, ale istnieje 5 segmentów, które muszą być łączone w sumie (dwa podane plasterki i części listy przed/między nimi/po nich). – interjay

+0

@interjay Dlaczego 5 segmentów? Obawiam się, że nie widziałem sensu. – Will

+0

Spróbuj uruchomić swój kod i sprawdź, czy zapewnia wymagany wynik. – interjay

1

Myślę, że najlepiej jest używać łączenia i krojenia. Jeśli przekazujesz listę, a następnie dwie listy z parami indeksu, możesz po prostu podzielić listę i zmienić kolejność dwóch podlist. Zauważ, że zarówno pracują jak zwykłe cięcie, numer początkowy jest zawarty, ale końcowy nie jest.

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

można użyć normalnej techniki zamiany (x,y = y,x) tutaj, ale tylko wtedy, gdy wykona zamianę we właściwej kolejności: x musi być drugi (skrajna) plaster, natomiast y jest pierwszym (od lewej) plaster.

>>> 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] 

To działa, ponieważ będzie to przypisać do my_list[7:10] najpierw, a dopiero potem do my_list[2:4].

Jeśli wykonasz tę czynność w odwrotnej kolejności, przypisanie najpierw do my_list[2:4] spowoduje zmianę położenia pozycji po prawej z powodu podlisty o różnych długościach, co da nieprawidłowe wyniki.

Jeśli chodzi o wydajność, może to być lub nie być szybszy niż twój kod: prawdopodobnie zależy to od długości listy i wycinków. Będziesz musiał przetestować go na typowych przypadkach użycia, aby zobaczyć.

1

Jest to inny sposób to zrobić: wyjście

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 druk:

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

Niezupełnie oczywiste (lub wydajny), ale to działa. Byłem ciekawy, czy obiekt plastra może być dalej wykorzystywany.

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]))