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?
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.
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).
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.
a, b = b, a
Is a perfectly Pythonic idiom. It is short and readable, as long as your variable names are short enough.
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!
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
).
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With