#White #Dark #txt #download

        
"""
Equivalences

You have a working code, and you want it to be more clean, more pretty, more readable.
This is what we call, refactoring.

Here is a list of transformation to help you in this task.
You can of course choose to apply the transformation or not.

A "→" means the code will probably be more readable (according to me).

A "↔" means the clarity will depend on the context (neither code is a priori more readable).
"""

##
# inverser if/else 
##
if CONDITION:
    A
else:
    B
# ↔
if not(CONDITION):
    B
else:
    A

## example 1
if a == 5:
    print("hello")
else:
    waw = 2
# ↔ (invert if/else)
if not(a == 5):
    waw = 2
else:
    print("hello")
# ↔ (not == ↔ !=)
if a != 5:
    waw = 2
else:
    print("hello")

###
# else do nothing
###
if CONDITION:
    A
else:
    pass  # do nothing
# → 
if CONDITION:
    A

## example 1
if a != 5:
    print("hello")
else:
    pass  # do nothing
# → ("else do nothing" is useless)
if a != 5:
    print("hello")

## example 2
if a == 5:
    pass  # do nothing
else:
    print("hello")
# → (invert if/else)
if a != 5:
    print("hello")
else:
    pass  # do nothing
# → ("else do nothing" is useless)
if a != 5:
    print("hello")
    
###
# simplify not (De Morgan's laws)
###
# De Morgan on "and"
if not(A and B):
    ...
# ↔
if (not A) or (not B):
    ...

# De Morgan on "or"
if not(A or B):
    ...
# ↔
if (not A) and (not B):
    ...

## example 1
if not(a > 10 or a == 5):
    print('hello')
# → (De Morgan)
if a <= 10 and a != 5:
    print('hello')
    
## example 2
if a > 10 or a == 5:
    pass
else:
    print('hello')
# → (invert if/else)
if not(a > 10 or a == 5):
    print('hello')
else:
    pass
# → ("else do nothing" is useless)
if not(a > 10 or a == 5):
    print('hello')
# → (De Morgan)
if a <= 10 and a != 5:
    print('hello')

###
# if variable 
###
if CONDITION:
    x = A
else:
    x = B
# →
x = A if CONDITION else B
# →
x = (A if CONDITION else B)
# →
x = (A if CONDITION else
     B)

## example
if a == 5:
    c = 2
else:
    c = 0
# → ("one-line if" also called "ternary operator" or "functional if")
c = (5 if a == 5 else 0)
# ↔ (parenthesis are useless)
c = 5 if a == 5 else 0

##
# if elif cascade on variable
##
if CONDITION:
    x = A
elif CONDITION_2:
    x = B
elif CONDITION_3:
    x = C
else:
    x = D
# → 
x = (A if CONDITION else
     B if CONDITION_2 else
     C if CONDITION_3 else
     D)

## example
if a == 5:
    c = 8
elif a == 2:
    c = 4
elif a < 0:
    c = 1
else:
    c = 0
# → (functional if)
c = (8 if a == 5 else
     4 if a == 2 else
     1 if a < 0 else
     0)

##
# renaming
##
#
# You can rename a variable to give it a name more explicit :
e = v * t
i = e / 2.56
# →
distance = velocity * time
distance_inch = distance / 2.56
# Generally variable names of few letters are <strong>too short</strong>
# (except in mathematical expressions or well known variable names like the <code>"i"</code> in a loop)
# and variable names with more than three real words are <strong>too long</strong>
# (a comment next to the variable creation will be probably better).

## 
# inline variable
##
x = ...
operation(x)
# → (only possible if x is used only once)
operation(...)
## example
x = size + 1  # x depends on the size
y = size - 1  # y depends on the size
the_coefficent = x + 2 * y  # let's compute the coefficent using the linear formula
print(the_coefficent)       # let's print it

# ↔ (inline variable "the_coefficent")
x = size + 1  # x depends on the size
y = size - 1  # y depends on the size
print(x + 2 * y)  # let's print the result of the linear formula

# ↔ (inline variables "x" and "y")
print((size + 1) + 2 * (size - 1))  # let's print the result of the linear formula depending on the size

##
# boolean return
##
def f(...):
    ...
    if CONDITION:
        return True
    else:
        return False
# →
def f(...):
    ...
    return CONDITION

## example 1
def is_even(x):
    if x % 2 == 0:    # if the rest of division by 2 is 0
        return True   # Vrai, le nombre est pair
    else:             # sinon
        return False  # Faux, le nombre n'est pas pair
# → (boolean return)
def is_even(x):
    return x % 2 == 0  # x is even iff the rest of division by 2 is 0
# :
if is_even(4):
    ...
    
## example 2
def vowel(x):
    if x == 'a' or x == 'e' or x == 'i' or x == 'o' or x == 'u':
        return True
    else:
        return False
# → (boolean return)
def vowel(x):
    return x == 'a' or x == 'e' or x == 'i' or x == 'o' or x == 'u'  # x is a vowel iff x is 'a', 'e', 'i', 'o', 'u'
# :
if vowel('a'):  # if 'a' is a vowel
    ...

##
# == True 
##
# given
def is_even(x):
    if x % 2 == 0:  # if the rest of division by 2 is 0
        return True
    else:
        return False
# :
if is_even(4) == True:  # si the is_even function returns True
    ...
# →
if is_even(4):  # if 4 is even
    ...

##
# or
##
if CONDITION:
    A
elif CONDITION_2:
    A  # same A
# →
if CONDITION or CONDITION_2:
    A
    
## example
if a == 5:
    x = 2
elif a > 10:
    x = 2
# → (or)
if a == 5 or a > 10:
    x = 2
    
##
# or else
##
if CONDITION:
    A
elif CONDITION_2:
    A  # same A
else:
    B
# →
if CONDITION or CONDITION_2:
    A
else:
    B

## example
if a == 5:
    x = 2
elif a > 10:
    x = 2
else:
    print('error')
# → (or)
if a == 5 or a > 10:
    x = 2
else:
    print('error')

##
# or return
##
def f(...):
    ...
    if CONDITION:
        return True
    if CONDITION_2:
        return True
    return False
# →
def f(...):
    ...
    return CONDITION or CONDITION_2
# ↔
def f(...):
    ...
    return (CONDITION
            or CONDITION_2)

## example
def interesting(x):
    if x > 10:  # if x > 10
        return True  # it's interesting
    if x == 5:  # if x == 5
        return True  # it's interesting
    return False  # otherwise, it's not interesting
# → (or return)
def interesting(x):
    return x > 10 or x == 5  # x is interesting if it's > 10 or 5

##
# and
##
if CONDITION:
    if CONDITION_2:
        A
# →
if CONDITION and CONDITION_2:
    A

## example
if a == 5:
    if a > 10:
        print('waw')
# → (and)
if a == 5 and a > 10:
    print('waw')

##
# and else
##
if CONDITION:
    if CONDITION_2:
        A
    else:
        B
else:
    B  # same b
# →
if CONDITION and CONDITION_2:
    A
else:
    B

## example
if a == 5:
    if b > 10:
        waw = 2 
    else:
        print('error')
else:
    print('error')
# → (and)
if a == 5 and b > 10:
    waw = 2
else:
    print('error')

##
# if return
##
def f(...):
    ...
    if CONDITION:
        return X
    ...
# ↔
def f(...):
    ...
    if CONDITION:
        return X
    else:
        ...

## example
def f(x):
    if x < 0:
        return -1
    else:
        y = x + 2
        z = y ** 2
        return z
# → (if return)
def f(x):
    if x < 0:
        return -1
    y = x + 2
    z = y ** 2
    return z

# I generally do that when the <code>"if"</code> is really short like a simple <code>"return"</code>.
# Souvent, ce sont des cas particuliers ou des cas de base, le code du bas est plus intéressant.

##
# for if return True (∃)
## for-if-return-True, any, exists, ∃ 
# Here is how we code a "∃"
def f(...):
    ...
    for x in L:
        if condition:  # this "if" DOESN'T have a "else"
            return True
    return False
# → (en python, il y a "all")
def f(...):
    ...
    return any(condition for x in L)
# ↔
def f(...):
    ...
    return any(condition
               for x in L)

# Note: in python there is also the [for...else](https://stackoverflow.com/questions/9979970/why-does-python-use-else-after-for-and-while-loops#9980752) but not so much people use it

## example
def contains_a_negative(L):
    for x in L:  # for each element in the list
        if x < 0:  # if it's < 0
            return True  # the list contains_a_negative
    return False  # in the end, it means it doesn't contain one
# → (any)
def contains_a_negative(L):
    return any(x < 0 for x in L)
# We'll read it as <em>A list L contains_a_negative if...</em>
# <ul>
# <li> there is a x < 0
# <li> there exists any x such that x < 0
# <li> ∃ x ∈ L: x < 0
# </ul>

##
# for if return False (∀)
## for-if-return-False, all, forall, ∀
# Here is how we code a "∀"
def f(...):
    ...
    for x in L:
        if condition:  # this "if" DOESN'T have a "else"
            return False
    return True
# → (en python, il y a "all")
def f(...):
    return all(not condition for x in L)
# ↔
def f(...):
    return all(not condition
               for x in L)

# Note: in python there is also the [for...else](https://stackoverflow.com/questions/9979970/why-does-python-use-else-after-for-and-while-loops#9980752) but not so much people use it

## example
def totally_positive(L):
    for x in L:  # for each element in the list
        if x < 0:  # if it's < 0
            return False  # the list is not totally_positive
    return True  # in the end, the list is totally_positive
# → (all)
def totally_positive(L):
    return all(x >= 0 for x in L)
# We'll read it as <em>A list L is totalement_positive if</em>...
# <ul>
# <li> A list is totally positive if all its elements x are >= 0
# <li> for all its elements x one have x >= 0
# <li> any element x ∈ L satisfies x >= 0
# <li> ∀ x ∈ L : x >= 0
# </ul>

##
# not ∀/∃ (De Morgan's laws)
## not-any, not-all
# De Morgan on "∀"
not all(condition for x in L)
# →
any(not condition for x in L)

# De Morgan on "∃"
not any(condition for x in L)
# →
all(not condition for x in L)

## example
if not all(x >= 0 for x in L):  # si on n'a pas tous les nombres >= 0
    ...
# → (if non empty)
if any(x < 0 for x in L):  # c'est qu'il existe un nombre < 0
    ...
# <strong>Attention</strong>: cette transformation ne marche pas si L est vide !
#

##
# for if return else return
##
# Here is how one code a linear search
def f(...):
    for x in L:
        if condition:
            return a
    return b
# → (in python, one can use "next")
def f(...):
    return next((a for x in L if condition), b)
# ↔
def f(...):
    return next((a for x in L if condition),
                b)

# Note: in python there is also the [for...else](https://stackoverflow.com/questions/9979970/why-does-python-use-else-after-for-and-while-loops#9980752) but not so much people use it

## example
#
# <em>Le super_nombre d'une liste est le <strong>premier</strong> x dans la liste tel que x > 10</em> :
def super_number(L):
    for x in L:  # for each element in the list
        if x > 10:  # if it's > 10
            return x  # it's the super_number of that list
    return 0  # il n'y a pas de super nombre, on renvoie 0
# →
def super_number(L):
    return next((x for x in L if x > 10), 0)

##
# for append
##
L = []
for x in iterable:
    L.append(e)
# →
L = [e for x in iterable]

##
# for append f(x)
## +, map
L = []
for x in iterable:
    L.append(f(x))
# →
L = list(map(f, iterable))
# ↔
L = [f(x) for x in iterable]

##
# for if append
## 
L = []
for x in iterable:
    if condition:
        L.append(e)
# →
L = [e for x in iterable if condition]

##
# for if f(x) append x
## +, filter
L = []
for x in iterable:
    if f(x):
        L.append(x)
# →
L = list(filter(f, iterable))
# ↔
L = [x for x in iterable if f(x)]

##
# iterate a generator (python)
##
for x in list(generator):
    ...
# →
for x in generator:
    ...

## example 1
for x in list(map(f, L)):  # map, filter, zip...
    ...
# →
for x in map(f, L):
    ...

## example 2
# with
def operation(x):
    return (x + 1) * 2 - x
# :
for x in list(map(operation, [1,2,3])):
    print(x)
# →
for x in map(operation, [1,2,3]):
    print(x)

##
# sum
##

## example
s = 0
for x in L:
    s += a
# → (sum)
s = sum(a for x in L)

# technically, "sum" is a particular case of "reduce" but "reduce" is a bit useless in python

##
# in tuple (python)
##

## example
if x == 'a' or x == 'e' or x == 'i' or x == 'o' or x == 'u':
    ...
# → (in)
if x in ('a', 'e', 'i', 'o', 'u'):
    ...

# it's a particular case of linear search in a list