Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pythonic Swap?

Tags:

python

swap

I found that I have to perform a swap in python and I write something like this:

arr[first], arr[second] = arr[second], arr[first]

I suppose this is not so pythonic. Does somebody know how to do a swap in python more elegant?

EDIT: I think another example will show my doubts:

self.memberlist[someindexA], self.memberlist[someindexB] = self.memberlist[someindexB], self.memberlist[someindexA]

is this the only available solution for swap in python?

like image 547
jagttt Avatar asked Jul 19 '09 12:07

jagttt


People also ask

Is there a swap in Python?

A simple swap function in Python is generally considered a function that takes two initialized variables, a = val_a and b = val_b , and returns a result of a = val_b and b = val_a . The function accepts variables of arbitrary types, or more precisely, variables that are assigned with objects of arbitrary types.

How do you swap two variables?

The bitwise XOR operator can be used to swap two variables. The XOR of two numbers x and y returns a number that has all the bits as 1 wherever bits of x and y differ. For example, XOR of 10 (In Binary 1010) and 5 (In Binary 0101) is 1111, and XOR of 7 (0111) and 5 (0101) is (0010).

How do you swap numbers in Python?

The simplest way to swap the values of two variables is using a temp variable. The temp variables is used to store the value of the fist variable ( temp = a ). This allows you to swap the value of the two variables ( a = b ) and then assign the value of temp to the second variable.


4 Answers

a, b = b, a

Is a perfectly Pythonic idiom. It is short and readable, as long as your variable names are short enough.

like image 152
Adam Matan Avatar answered Oct 12 '22 23:10

Adam Matan


The one thing I might change in your example code: if you're going to use some long name such as self.memberlist over an over again, it's often more readable to alias ("assign") it to a shorter name first. So for example instead of the long, hard-to-read:

self.memberlist[someindexA], self.memberlist[someindexB] = self.memberlist[someindexB], self.memberlist[someindexA]

you could code:

L = self.memberlist
L[someindexA], L[someindexB] = L[someindexB], L[someindexA]

Remember that Python works by-reference so L refers to exactly the same object as self.memberlist, NOT a copy (by the same token, the assignment is extremely fast no matter how long the list may be, because it's not copied anyway -- it's just one more reference).

I don't think any further complication is warranted, though of course some fancy ones might easily be conceived, such as (for a, b "normal" indices >=0):

def slicer(a, b):
  return slice(a, b+cmp(b,a), b-a), slice(b, a+cmp(a,b), a-b)

back, forth = slicer(someindexA, someindexB)
self.memberlist[back] = self.memberlist[forth]

I think figuring out these kinds of "advanced" uses is a nice conceit, useful mental exercise, and good fun -- I recommend that interested readers, once the general idea is clear, focus on the role of those +cmp and how they make things work for the three possibilities (a>b, a<b, a==b) [[not for negative indices, though -- why not, and how would slicer need to change to fix this?]]. But using such a fancy approach in production code would generally be overkill and quite unwarranted, making things murkier and harder to maintain than the simple and straightforward approach.

Remember, simple is better than complex!

like image 22
Alex Martelli Avatar answered Oct 12 '22 21:10

Alex Martelli


It's difficult to imagine how it could be made more elegant: using a hypothetical built-in function ... swap_sequence_elements(arr, first, second) elegant? maybe, but this is in YAGGI territory -- you aren't going to get it ;-) -- and the function call overhead would/should put you off implementing it yourself.

What you have is much more elegant than the alternative in-line way:

temp = arr[first]
arr[first] = arr[second]
arr[second] = temp

and (bonus!) is faster too (on the not unreasonable assumption that a bytecode ROT_TWO is faster than a LOAD_FAST plus a STORE_FAST).

like image 20
John Machin Avatar answered Oct 12 '22 23:10

John Machin


a, b = b, a is about as short as you'll get, it's only three characters (aside from the variable names).. It's about as Python'y as you'll get

One alternative is the usual use-a-temp-variable:

self.memberlist[someindexA], self.memberlist[someindexB] = self.memberlist[someindexB], self.memberlist[someindexA]

..becomes..

temp = self.memberlist[someindexB]
self.memberlist[someindexB] = self.memberlist[someindexA]
self.memberlist[someindexA] = temp

..which I think is messier and less "obvious"

Another way, which is maybe a bit more readable with long variable names:

a, b = self.memberlist[someindexA], self.memberlist[someindexB]
self.memberlist[someindexA], self.memberlist[someindexB] = b, a
like image 1
dbr Avatar answered Oct 12 '22 21:10

dbr