2015-06-29 3 views
16

Учитывая следующий список:Перестановка двух подсписки в списке

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

Я хочу, чтобы иметь возможность поменять подсписком my_list[2:4] с подсписком my_list[7:10], как быстро и эффективно, насколько это возможно, чтобы получить новый список:

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

Вот моя попытка:

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

Это печать де но этот способ делать это выглядит ужасно для меня.

Есть ли более простой и элегантный способ сделать это, что не будет создавать четыре новых списка для каждого вызова функции? (Я планирую назвать эту функцию много)

Я не против (на самом деле я бы предпочел) изменить исходный список, а не создавать новый экземпляр каждого вызова функции.

+2

Как насчет 'my_list [2: 4] = my_list [7:10]'? – Moritz

+2

Это перезапишет 'my_list [2: 4]'. –

+0

Я не понимаю, потому что он создает: '[0, 1, 7, 8, 9, 4, 5, 6, 7, 8, 9, 10, 11, 12]' – Moritz

ответ

25

Ломтики могут быть назначены.

Две переменные могут быть заменены на a, b = b, a.

Объединить два выше ::

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

берегись, - если ломтики имеют разные размеры - важен порядок: Если поменять в обратном порядке, вы в конечном итоге с другой результат, потому что он сначала изменит начальные элементы (нижние индексы), а затем более высокие индексы (но они будут перенесены в другую позицию по первому назначению).

Кроме того, срезы не должны пересекаться.

+0

Отлично. Это выглядит намного лучше и проще, а также изменяет оригинал - что предпочтительнее. Спасибо. –

+3

Да, вы не можете поменять список в обратном порядке. Если использовать функцию, мы можем сначала судить о границе двух диапазонов. – Will

+1

Угловой футляр, который терпит неудачу с этим, является перекрывающимся диапазоном ... однако я не уверен, что они производят какой-либо значимый результат в любом случае ... – Bakuriu

0

Я думаю, что лучше использовать индекс списка в качестве параметров.

Если вы хотите, чтобы пересмотреть свою заменить фикцию, как это:

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 

Я установил его.

+1

Невозможно работать правильно. Он выполняет только три среза, но есть 5 сегментов, которые должны быть объединены в общей сложности (два указанных фрагмента и части списка до/между ними/после них). – interjay

+0

@interjay Почему 5 сегментов? Боюсь, я не видел смысла. – Will

+0

Попробуйте запустить код и посмотреть, дает ли он требуемый результат. – interjay

1

Я думаю, что лучше всего использовать конкатенацию и нарезку. Если вы передадите список, а затем два списка с парами индексов, вы можете просто нарезать список и перегруппировать два подсписок. Обратите внимание, что indexA и indexB оба работают в некотором роде как обычная нарезка, стартовый номер включен, но в конце нет.

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

Вы можете использовать обычный метод свопинга (x,y = y,x) здесь, но только если вы выполняете своп в правильном порядке: x должен быть второй (крайний справа) срез, в то время как y является первым (крайний слева) срез.

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

Это работает, потому что он будет назначать my_list[7:10] первым, и только потом my_list[2:4].

Если вы выполняете это в обратном порядке, то присвоение my_list[2:4] сначала изменит местоположение элементов справа из-за подписок, имеющих разную длину, что даст неправильные результаты.

По производительности, это может быть или не быть быстрее, чем ваш код: он, вероятно, зависит от длины списка и фрагментов. Вам нужно будет проверить его на типичных случаях использования.

1

Это другой способ сделать это: выход

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 печати:

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

Не совсем очевидно (или эффективный), но она работает. Мне было любопытно узнать, можно ли использовать объект среза.

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])) 
Смежные вопросы