Swapping two sublists in a list

雨燕双飞 提交于 2019-12-01 13:51:17

问题


Given the following list:

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

I want to be able to swap the sub-list my_list[2:4] with the sub-list my_list[7:10] as quickly and as efficiently as possible, to get the new list:

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

Here's my attempt:

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

This does print the desired output, although this way of doing it looks awful to me.

Is there a more easy and elegant way of doing it, that will not create four new lists for every function call? (I plan to call this function a lot)

I don't mind (actually I'd prefer) changing the original list, rather than creating new instance every function call.


回答1:


Slices can be assigned.

Two variables can be swapped with a, b = b, a.

Combine the two above::

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

Beware that - if slices have different sizes - the order is important: If you swap in the opposite order, you end up with a different result, because it will change first the initial items (lower indices), and then the higher index items (but those will be shifted in a different position by the first assignment).

Also, slices must not overlap.




回答2:


You can use normal swapping technique (x,y = y,x) here, but only if you perform the swap in the correct order: x must be the second (rightmost) slice, while y is the first (leftmost) slice.

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

This works because it will assign to my_list[7:10] first, and only then to my_list[2:4].

If you perform this in the reverse order, assigning to my_list[2:4] first will change the location of the items on the right due to the sublists having different lengths, which will give incorrect results.

Performance-wise, this may or may not be faster than your code: it probably depends on the length of the list and the slices. You will have to test it on typical use-cases to see.




回答3:


I think it's best to use concatenation and slicing. If you pass the list and then two lists with index pairs then you can just slice apart the list and rearrange the two sublists. Note that indexA and indexB both work in the some way as regular slicing, the start number is included but the end one is not.

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



回答4:


Not exactly obvious (or efficient) but it works. I was curious to see if the slice object could be further utilised.

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



回答5:


This is an other way to do it:

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 print output:

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



回答6:


I think it's much better to use list index as parameters.

If you'd like to redefine your replace fuction like this:

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

I have fixed it.



来源:https://stackoverflow.com/questions/31111258/swapping-two-sublists-in-a-list

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!