Переключение двух списков в список
Учитывая следующий список:
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])
Это напечатает желаемый результат, хотя этот способ делать это выглядит ужасно для меня.
Есть ли более простой и элегантный способ сделать это, который не будет создавать четыре новых списка для каждого вызова функции? (Я планирую многократно называть эту функцию)
Я не возражаю (на самом деле, я бы предпочел) изменить исходный список, а не создавать новый экземпляр при каждом вызове функции.
Ответы
Ответ 1
Можно назначить срезы.
Две переменные могут быть заменены на 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]
Остерегайтесь того, что - если срезы имеют разные размеры - важно порядок: если вы меняете в обратном порядке, вы получаете другой результат, потому что он сначала изменит начальную (нижние индексы), а затем более высокие индексы (но они будут сдвинуты в другую позицию по первому назначению).
Кроме того, срезы не должны перекрываться.
Ответ 2
Здесь вы можете использовать обычную технику свопинга (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]
изменит расположение элементов справа из-за подписок, имеющих разную длину, что даст неверные результаты.
По производительности, это может быть или не быть быстрее, чем ваш код: это, вероятно, зависит от длины списка и фрагментов. Вам придется протестировать его в типичных случаях использования.
Ответ 3
Не совсем очевидно (или эффективно), но он работает. Мне было любопытно узнать, можно ли использовать объект среза.
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]))
Ответ 4
Я думаю, что лучше всего использовать конкатенацию и нарезку. Если вы передадите список, а затем два списка с парами индексов, вы можете просто нарезать список и перегруппировать два подсписок. Обратите внимание, что 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
Это другой способ сделать это:
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]
Ответ 6
Я думаю, что гораздо лучше использовать индекс списка в качестве параметров.
Если вы хотите переопределить свою замену fuction следующим образом:
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
Я исправил его.