I realized that instead of using negative numbers to access elements of a list from the end, we can just use bitwise NOT. That looks more symmetrical (and hence beautiful).
For a list x:
First element is x[0]
Last element is x[~0] (instead of x[-1])
You can use x[~0], x[~1], x[~2]... (coz ~0==-1, ~1==-2 etc)
Did you guys know this already or is this my fresh insight? If it is the latter, YAY! :-)
I didn't know that, but I don't know that it really is that helpful. I prefer the Pythonic way of sticking to one method and having anyone be able to understand it.
Good little hack though, if it works for you go nuts! (but document it somewhere and be consistent)
I believe this'll only work on machines that use 2s-complement arithmetic, which is basically all of them. Just saying...it's theoretically possible to have number representations where ~0 != -1.
I don't get it, either. I mean, I realize that the OP's method would be obscure to someone who's never seen it, but at least on some level, it's more intuitive. Your example is simply obfuscated code for no other reason (other than humor, apparently, which like I said, I missed).
Look at this code I wrote for Project Euler. it checks if a sequence is "palindromic". A "palindromic" sequence reads the same both from left and from right. So the simple idea is to check from the left of the sequence to the middle, and compare each element during the process with ones read from the right. Note here I use Python 2.5 integer division (//) to ensure the index is integer.
Using official Python index syntax, I have to write "s[i] == s[-i-1]" to compare elements on symmetric positions in the sequence.
def ispalindromic(s):
return all(s[i] == s[-i-1] for i in range(len(s)//2))
However, using the "bitwise or" trick proposed above, I just write "s[i] == [s~i]", really neat!
def ispalindromic(s):
return all(s[i] == s[~i] for i in range(len(s)//2))
Clever, but as others pointed out likely to anger anyone who has to read your code.
NB: python bitwise operations are not super fast like in C. They don't get optimized down to single CPU instructions but instead are looked up like regular type methods (e.g. __str__ and __add__). An "ob[~0]" won't kill you even in a loop but don't bother translating simple math into bit-twiddling because it won't help (and might hurt if it inflates the number of operations).
import cProfile
def flipbits():
c=0
for i in range(1,400000):
b=~i
c=c+b
print c
def negnums():
c=0
for i in range(1,400000):
b=-i
c=c+b
print c
cProfile.run("flipbits()")
140 function calls in 0.175 CPU seconds
cProfile.run("negnums()")
140 function calls in 0.176 CPU seconds
---
Summary:
Flipping bits is tiny bit faster actually.To make negnums function produce the same result as flipbits, we need to change b=-i to b=-i-1 and this is even slower. Poke holes in my experiment please.
I was under the impression that Python will do constant folding when it compiles to bytecode. In that case, shouldn't "~0" be exactly as fast as "-1" at runtime?