Skip to content

vhoulbreque/python-golf-cheatsheet

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

14 Commits
 
 
 
 

Repository files navigation

python-golf-cheatsheet

This is a golf cheatsheet that lists techniques to reduce the number of chars in Python code.

INTEGERS

Check if a number is a power of 2

n&~-n  # zero for powers of 2, non-zero for others
# or
n&~-n<1
# or
n&-n-n  # zero for powers of 2, non-zero for others
# or
n&-n==n

instead of

(n & (n-1) == 0) and n != 0
# or
import math;math.log(n, 2).is_integer()
# or
bin(num).count("1") == 1

Check if a number is a power of q

q**n%n  # zero for powers of q, non-zero for others
# or
q**n%n<1

instead of

import math;math.log(n, q).is_integer()

STRINGS

Generate the entire alphabet

map(chr,range(65,91))
# ABCDEFGHIJKLMNOPQRSTUVWXYZ

map(chr,range(97,123))
# abcdefghijklmnopqrstuvwxyz

instead of:

"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
[chr(i+97)for i in range(26)]

Extended slicing

for i in 0,1,2:
    print("fbboaaorz"[i::3])
# foo
# bar
# baz

instead of:

for i in 0,1,2:
    if i == 0:
        print("foo")
    elif i == 1:
        print("bar")
    else:
        print("baz")

It works with strings that are the same size (+- 1 char). For True and False, see:

print("FTarlusee"[condition::2])
# False (if condition is False)
# True (if condition is True)

Check if a string starts with a given prefix p

p<=s<p+"􏿽"  # last utf-8 char
# or
p<=s<p+"~"  # last printable ascii char

instead of:

s.startswith(p)

NB: See the utf-8 list to see the last char.

Replace chars

"ATTCGAAGCCTTC".translate({65:84,84:"U"})  # "TUUCGTTGCCUUC"
"ATTCGAAGCCTTC".translate({65:84,84:"55"})  # "T5555CGTTGCC5555C"
"ATTCGAAGCCTTC".translate({65:84,84:65})  # "TAACGTTGCCAAC"

instead of:

"ATTCGAAGCCTTC".replace("T","U").replace("A","T")  # "TUUCGTTGCCUUC"
"ATTCGAAGCCTTC".replace("T","55").replace("A","T")  # "T5555CGTTGCC5555C"
"ATTCGAAGCCTTC".replace("A","~").replace("T","A").replace("~","T")  # "TAACGTTGCCAAC"

Explanation: replace is costly because you have to use it once for every replacement you want to make. Moreover, when you need to exchange 2 chars ("A" -> "T" and "T" to "A"), you are forced to make one more .replace call for the exchange to give the correct result.

ITERABLES

Get the last element of a list

L=[1,3,4,8]
*_,a=L
# a = 8

instead of:

L=[1,3,4,8]
a=L[-1]
# a = 8

Get an element from the back of a list

L=[1,2,3,4,5]
i=3
a=L[~i]  # 2

instead of

L=[1,2,3,4,5]
i=3
a=L[-i-1]  # 2

Explanation: ~ is the bitwise inversion, leading to ~i being equal to -i-1.

Add an element to a list

L=[1,2,3,4,5]
a=6
L+=a,

instead of

L=[1,2,3,4,5]
a=6
L+=[a]
# or
L.append(a)

Add 2 lists together

L=[1,2,3]
M=[4,5,6]
L+=M

instead of

L=[1,2,3]
M=[4,5,6]
L.extend(M)

LOOPS

Loop on small range

for i in 0,1,2:

instead of

for i in range(3):

CAVEAT: it works only for loops of up until range(3) included.

Loop when index is not used

exec("do_something;"*n)

instead of

for _ in range(n):do_something

Loop on reverse

i=n;exec("do_something;i-=1;"*n)

instead of

for i in range(n,0,-1):do_something

Merge 2 for loops together

for i in range(m*n):
    print(i//n, i%n)

instead of

for i in range(m):
    for j in range(n):
        print(i, j)

Merge 3 for loops together

for i in range(m*n*o):
    print(i//n//o, i%(n*o)//o, i%o)

instead of

for i in range(m):
    for j in range(n):
        for k in range(o):
            print(i, j, k)

CONDITIONS

Ternary operation

s=[x,y][b]

instead of:

s = y if b else x

CAVEAT: b must be True, False, 0 or 1. Being "truthy"/"untruthy" is not sufficient.

Ternary operation for numbers

For x and y numbers and b a boolean:

do instead of
y*b [0,y][b]
y**b [1,y][b]
b or x [x,1][b]
x+b [x,x+1][b]
x-b [x,x-1][b]
x+z*b [x,y][b]*

* only works if z=y-x already exists.

For x and y integers and b a boolean:

do instead of
1|-b [1,-1][b]
x^-b [x,~x][b]
-x-b [-x,~x][b]

Check the first element of a list

L=[1,3,4,8]
M=[]
L[:1]==[1]  # True
L[:1]==[2]  # False
M[:1]==[1]  # False

instead of

L=[1,3,4,8]
M=[]
next(iter(L),None)==1  # True
next(iter(L),None)==2  # False
next(iter(M),None)==1  # False

Slicing the list is always possible, therefore [][:1] does not fail and just returns []. [][0] would fail. The interesting part is that it works when the list is empty and when the list contains at least an element with the same expression.

MISC

Instantiate several variables

a=b=c=d=0
e,f=1,2

instead of:

a = 0
b = 0
c = 0
d = 0
e = 1
f = 2

CAVEAT: a=b=c=d=[] does not work with lists. Indeed:

a=b=c=d=[]
a.append(1)
print(a, b, c, d)  # [1] [1] [1] [1]

Releases

No releases published

Packages

No packages published