Elegant method to replace unequal list fragments?

I studied replacing items in lists on this site, but in most cases itโ€™s about replacing one item with another.

Here I am trying to change the position of pieces of unequal length. List of examples:

x = [6,2,4,3,4,1,4,5] 

I was hoping for the elegant way used to exchange values โ€‹โ€‹in lists and variables in general, such as the form below:

 x[0:1], x[1:7] = x[1:7], x[0:1] #Expected output x = [2, 4, 3, 4, 1, 4, 5, 6] 

It is not surprising that it does not work, it changes the first two elements:

 #Actual output x = [2, 6, 4, 3, 4, 1, 4, 5] 

Another example: Swap x[0:4] with x[5:7] :

 #Expected output x = [1, 4, 4, 6, 2, 4, 3, 5] 

I hope it is clear that the exchange happens in such a way that the first slice1 element takes the previous location of the first slice2 element. The rest follows.

Is there an easy way to do this elegantly and efficiently?

+5
source share
4 answers

You can use collections.deque to rotate values:

 import collections x = [6,2,4,3,4,1,4,5] d = collections.deque(x) d.rotate(-1) print(d) 

Output:

 [2, 4, 3, 4, 1, 4, 5, 6] 
+1
source

An easy way to do this with just lists is to directly slice the concatenation:

 x = [6,2,4,3,4,1,4,5] x = x[1:] + x[:1] print x 

Output:

 [2, 4, 3, 4, 1, 4, 5, 6] 

In the second case, you cut it into three parts in the same way.


Analysis of the submitted error:

Your assignment attempt has an irregular shape: multiple assignment is performed by the expression in the expression, and not as a stream of values. What you entered breaks down into parallel evaluation and assignments

 x[0:1] = x[1:7] x[1:7] = x[0:1] 

If you do this individually, you will see that the assignment is limited to a smaller fragment in each case.

0
source

I donโ€™t think there is any elegant, completely general way. Here's a not-so-elegant way:

 def swapslices(l, from1, to1, from2, to2): if not (from1 <= to1 <= from2 <= to2): raise ValueError('slices out of order or overlapping') if to1 - from1 == to2 - from2: # Easy case. No need to shift the part between the two slices. l[from1: to1], l[from2, to2] = l[from2: to2], l[from1: to1] else: # Hard case. We need to rewrite the whole section. l[from1: to2] = l[from2: to2] + l[to1: from2] + l[from1: to1] 

This function requires you to go through the bottom slice first and not try to use slices, like 6:3 .

The function relies on the fact that if you try to replace fragments a and c here:

 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] ---- ---- ------- abc 

this is equivalent to replacing the whole section a + b + c with c + b + a :

 [0, 5, 6, 7, 3, 4, 1, 2, 8, 9] ------- ---- ---- cba 

Example:

 >>> l = list(range(10)) >>> swapslices(l, 1, 3, 5, 8) >>> l [0, 5, 6, 7, 3, 4, 1, 2, 8, 9] 
0
source

I think this should be enough:

 def swapslices(lst, from1, to1, from2, to2): # assumes from1:to1 < from2:to2 def reverse(l, r): r = r - 1 while l < r: lst[l], lst[r] = lst[r], lst[l] l += 1 r -= 1 reverse(to1, from2) reverse(from2, to2) reverse(from1, to1) reverse(from1, to2) 

try using

 a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] swapslices(a, 2, 4, 6, 9) # a is now [0, 1, 6, 7, 8, 4, 5, 2, 3, 9, 10] 
0
source

Source: https://habr.com/ru/post/1273032/


All Articles