# Better way to swap elements in a list?

## Question:

I have a bunch of lists that look like this one:

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

I want to swap elements as follows:

``````final_l = [2, 1, 4, 3, 6, 5, 8, 7, 10, 9]
``````

The size of the lists may vary, but they will always contain an even number of elements.

I’m fairly new to Python and am currently doing it like this:

``````l =  [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
final_l = []
for i in range(0, len(l)/2):
final_l.append(l[2*i+1])
final_l.append(l[2*i])
``````

I know this isn’t really Pythonic and would like to use something more efficient. Maybe a list comprehension?

I don’t see anything wrong with your implementation at all. But you could perhaps do a simple swap instead.

``````l =  [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
for i in range(0, len(l), 2):
old = l[i]
l[i] = l[i+1]
l[i+1] = old
``````

EDIT
Apparently, Python has a nicer way to do a swap which would make the code like this

``````l =  [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
for i in range(0, len(l), 2):
l[i], l[i+1] = l[i+1], l[i]
``````

Here a single list comprehension that does the trick:

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

In [2]: [l[i^1] for i in range(len(l))]
Out[2]: [2, 1, 4, 3, 6, 5, 8, 7, 10, 9]
``````

The key to understanding it is the following demonstration of how it permutes the list indices:

``````In [3]: [i^1 for i in range(10)]
Out[3]: [1, 0, 3, 2, 5, 4, 7, 6, 9, 8]
``````

The `^` is the exclusive or operator. All that `i^1` does is flip the least-significant bit of `i`, effectively swapping 0 with 1, 2 with 3 and so on.

You can use the pairwise iteration and chaining to flatten the list:

``````>>> from itertools import chain
>>>
>>> list(chain(*zip(l[1::2], l[0::2])))
[2, 1, 4, 3, 6, 5, 8, 7, 10, 9]
``````

Or, you can use the `itertools.chain.from_iterable()` to avoid the extra unpacking:

``````>>> list(chain.from_iterable(zip(l[1::2], l[0::2])))
[2, 1, 4, 3, 6, 5, 8, 7, 10, 9]
``````
``````newList = [(x[2*i+1], x[2*i]) for i in range(0, len(x)/2)]
``````

Now find a way to unzip the tuples. I won’t do all of your homework.

Another way, create nested lists with pairs reversing their order, then flatten the lists with `itertools.chain.from_iterable`

``````>>> from itertools import chain
>>> l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> list(chain.from_iterable([[l[i+1],l[i]] for i in range(0,(len(l)-1),2)]))
[2, 1, 4, 3, 6, 5, 8, 7, 10, 9]
``````

EDIT: I just applied Kasramvd’s benchmark test to my solution and I found this solution is slower than the other top answers, so I wouldn’t recommend it for large lists. I still find this quite readable though if performance is not critical.

Here a solution based in the `modulo` operator:

``````l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
even = []
uneven = []
for i,item in enumerate(l):
if i % 2 == 0:
even.append(item)
else:
uneven.append(item)

list(itertools.chain.from_iterable(zip(uneven, even)))
``````

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 đź™‚

One of the possible answer using `chain` and `list comprehension`

``````>>> l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> list(chain([(l[2*i+1], l[2*i]) for i in range(0, len(l)/2)]))
[(2, 1), (4, 3), (6, 5), (8, 7), (10, 9)]
``````

Another approach with simply re-assigning and slicing technique

``````l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
for a in range(0,len(l),2):
l[a:a+2] = l[a-len(l)+1:a-1-len(l):-1]
print l
``````

output

``````[2, 1, 4, 3, 6, 5, 8, 7, 10, 9]
``````

## A benchmark between top answers:

Python 2.7:

``````('inp1 ->', 15.302665948867798) # NPE's answer
('inp2a ->', 10.626379013061523) # alecxe's answer with chain
('inp2b ->', 9.739919185638428) # alecxe's answer with chain.from_iterable
('inp3 ->', 2.6654279232025146) # Anzel's answer
``````

Python 3.4:

``````inp1 -> 7.913498195000102
inp2a -> 9.680125927000518
inp2b -> 4.728151862000232
inp3 -> 3.1804273489997286
``````

If you are curious about the different performances between python 2 and 3, here are the reasons:

As you can see @NPE’s answer (`inp1`) performs very better in python3.4, the reason is that in python3.X `range()` is a smart object and doesn’t preserve all the items between that range in memory like a list.

In many ways the object returned by `range()` behaves as if it is a list, but in fact it isnâ€™t. It is an object which returns the successive items of the desired sequence when you iterate over it, but it doesnâ€™t really make the list, thus saving space.

And that’s why in python 3 it doesn’t return a list while you slice the range object.

``````# python2.7
>>> range(10)[2:5]
[2, 3, 4]
# python 3.X
>>> range(10)[2:5]
range(2, 5)
``````

The second significant change is performance accretion of the third approach (`inp3`). As you can see the difference between it and the last solution has decreased to ~2sec (from ~7sec). The reason is because of the `zip()` function which in python3.X it returns an iterator which produces the items on demand. And since the `chain.from_iterable()` needs to iterate over the items once again it’s completely redundant to do it before that too (what that `zip` does in python 2).

Code:

``````from timeit import timeit

inp1 = """
[l[i^1] for i in range(len(l))]
"""
inp2a = """
list(chain(*zip(l[1::2], l[0::2])))
"""
inp2b = """
list(chain.from_iterable(zip(l[1::2], l[0::2])))
"""
inp3 = """
l[::2], l[1::2] = l[1::2], l[::2]
"""

lst = list(range(100000))
print('inp1 ->', timeit(stmt=inp1,
number=1000,
setup="l={}".format(lst)))
print('inp2a ->', timeit(stmt=inp2a,
number=1000,
setup="l={}; from itertools import chain".format(lst)))
print('inp2b ->', timeit(stmt=inp2b,
number=1000,
setup="l={}; from itertools import chain".format(lst)))
print('inp3 ->', timeit(stmt=inp3,
number=1000,
setup="l={}".format(lst)))
``````

For fun, if we interpret “swap” to mean “reverse” in a more general scope, the `itertools.chain.from_iterable` approach can be used for subsequences of longer lengths.

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

def chunk(list_, n):
return (list_[i:i+n] for i in range(0, len(list_), n))

list(chain.from_iterable(reversed(c) for c in chunk(l, 4)))
# [4, 3, 2, 1, 8, 7, 6, 5, 10, 9]
``````

An(other) alternative:

``````final_l = list() # make an empty list
for i in range(len(l)): # for as many items there are in the original list
if i % 2 == 0: # if the item is even
final_l.append(l[i+1]) # make this item in the new list equal to the next in the original list
else: # else, so when the item is uneven
final_l.append(l[i-1]) # make this item in the new list equal to the previous in the original list
``````

This assumes that the original list has an even number of items. If not, a try-except can be added:

``````final_l = list()
for i in range(len(l)):
if i % 2 == 0:
try: # try if we can add the next item
final_l.append(l[i+1])
except:  # if we can't (because i+1 doesnt exist), add the current item
final_l.append(l[i])
else:
final_l.append(l[i-1])
``````

A way using Numpy

``````import numpy as np

l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
l = np.array(l)
final_l = list(np.flip(l.reshape(len(l)//2,2), 1).flatten())
``````

swap = [2, 1, 4, 3, 5]

``````lst = []
for index in range(len(swap)):
if index%2 == 0 and index < len(swap)-1:
swap[index],swap[index+1]  = swap[index+1],swap[index]
lst.append(swap[index])
print(lst)

out = [1, 2, 3, 4, 5]
``````
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.