Swapping List Elements Effectively in Python

Fastest way to swap elements in Python list

Looks like the Python compiler optimizes out the temporary tuple with this construct:

code:

import dis

def swap1():
a=5
b=4
a, b = b, a

def swap2():
a=5
b=4
c = a
a = b
b = c

print 'swap1():'
dis.dis(swap1)
print 'swap2():'
dis.dis(swap2)

output:

swap1():
6 0 LOAD_CONST 1 (5)
3 STORE_FAST 0 (a)

7 6 LOAD_CONST 2 (4)
9 STORE_FAST 1 (b)

8 12 LOAD_FAST 1 (b)
15 LOAD_FAST 0 (a)
18 ROT_TWO
19 STORE_FAST 0 (a)
22 STORE_FAST 1 (b)
25 LOAD_CONST 0 (None)
28 RETURN_VALUE
swap2():
11 0 LOAD_CONST 1 (5)
3 STORE_FAST 0 (a)

12 6 LOAD_CONST 2 (4)
9 STORE_FAST 1 (b)

13 12 LOAD_FAST 0 (a)
15 STORE_FAST 2 (c)

14 18 LOAD_FAST 1 (b)
21 STORE_FAST 0 (a)

15 24 LOAD_FAST 2 (c)
27 STORE_FAST 1 (b)
30 LOAD_CONST 0 (None)
33 RETURN_VALUE

Two loads, a ROT_TWO, and two saves, versus three loads and three saves. You are unlikely to find a faster mechanism.

Better way to swap elements in a list?

No need for complicated logic, simply rearrange the list with slicing and step:

In [1]: l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

In [2]: l[::2], l[1::2] = l[1::2], l[::2]

In [3]: l
Out[3]: [2, 1, 4, 3, 6, 5, 8, 7, 10, 9]


 TLDR;

Edited with explanation

I believe most viewers are already familiar with list slicing and multiple assignment. In case you don't I will try my best to explain what's going on (hope I do not make it worse).

To understand list slicing, here already has an excellent answer and explanation of list slice notation.
Simply put:

a[start:end] # items start through end-1
a[start:] # items start through the rest of the array
a[:end] # items from the beginning through end-1
a[:] # a copy of the whole array

There is also the step value, which can be used with any of the above:

a[start:end:step] # start through not past end, by step

Let's look at OP's requirements:

 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]  # list l
^ ^ ^ ^ ^ ^ ^ ^ ^ ^
0 1 2 3 4 5 6 7 8 9 # respective index of the elements
l[0] l[2] l[4] l[6] l[8] # first tier : start=0, step=2
l[1] l[3] l[5] l[7] l[9] # second tier: start=1, step=2
-----------------------------------------------------------------------
l[1] l[3] l[5] l[7] l[9]
l[0] l[2] l[4] l[6] l[8] # desired output

First tier will be: l[::2] = [1, 3, 5, 7, 9]
Second tier will be: l[1::2] = [2, 4, 6, 8, 10]

As we want to re-assign first = second & second = first, we can use multiple assignment, and update the original list in place:

first , second  = second , first

that is:

l[::2], l[1::2] = l[1::2], l[::2]

As a side note, to get a new list but not altering original l, we can assign a new list from l, and perform above, that is:

n = l[:]  # assign n as a copy of l (without [:], n still points to l)
n[::2], n[1::2] = n[1::2], n[::2]

Hopefully I do not confuse any of you with this added explanation. If it does, please help update mine and make it better :-)

Swap values in the list in Python

Handling edges of algorithms used to be a real pain when I just started learning programming, and I believe so do you this time.

The two things you need to note here is

  • You start "inserting" at the second element, because the first element is always "sorted on its own". So you should change range(len(arr)) to range(1, len(arr)) for the outer loop.

  • You end with comparing and swapping the first two elements, i.e., arr[0] and arr[1], not arr[0] and arr[-1]. Python interprets negative indices as "counting from the end" so that causes another wave of mess unless handled properly.

    The change here is to end j before it reaches zero, so range(i, -1, -1) should be range(i, 0, -1).

Now your code runs fine after the above two patches.

def insert_sort(arr):
for i in range(1, len(arr)): # Start i from 1
for j in range(i, 0, -1): # End j at 1
if arr[j] < arr[j-1]:
arr[j-1], arr[j] = arr[j], arr[j-1]
print(arr)

return arr

insert_sort([5, 4, 3, 2, 1])
# [1, 2, 3, 4, 5]

swapping two elements between two lists in python

This does not come from your swap function that works with regular arrays It has to do with the fact that you are using numpy.array.

Here is a similar question I found.

You need to do TEMP_B = np.copy(B[j]) since Numpy copies data lazily.

How to switch position of two items in a Python list?

i = ['title', 'email', 'password2', 'password1', 'first_name', 
'last_name', 'next', 'newsletter']
a, b = i.index('password2'), i.index('password1')
i[b], i[a] = i[a], i[b]

I am trying to swap the two elements in the list, but after the first swap it keeps getting swapped as it fits the condition to be swapped

num = [3, 21, 5, 6, 14, 8, 14, 3]
num.reverse()
for i in range(len(num)-1):
if num[i] % 7 == 0:
num[i - 1], num[i] = num[i], num[i - 1]
num.reverse()
print("The required answer :", num)

Minimum swaping elements in a list to make it same like another list and count the swap in python

First, in order for swaps to make the lists equal, they must start with the same number of ones and zeros. So we can use a Counter to check for impossibility.

And second, a single swap necessarily fixes two differences. So we can just count the differences and divide by 2. We don't actually have to perform any of the swaps.

A demonstration:

from collections import Counter

def swap_count(xs, ys):
if xs == ys:
return 0
else:
cx = Counter(xs)
cy = Counter(ys)
if cx == cy:
n_diffs = sum(x != y for x, y in zip(xs, ys))
return n_diffs // 2
else:
return -1

def main():
tests = [
(2, [0, 1, 0, 1], [1, 0, 1, 0]),
(1, [0, 1, 0], [1, 0, 0]),
(-1, [0], [1]),
(0, [0, 1, 0, 1], [0, 1, 0, 1]),
]
for exp, xs, ys in tests:
n = swap_count(xs, ys)
print(n == exp, n, xs, ys)

main()

Output:

True 2 [0, 1, 0, 1] [1, 0, 1, 0]
True 1 [0, 1, 0] [1, 0, 0]
True -1 [0] [1]
True 0 [0, 1, 0, 1] [0, 1, 0, 1]


Related Topics



Leave a reply



Submit