"""

John Rachlin
DS 2000: Intro to Programming with Data

Filename: lol
    
Description: 

    
"""


#%% Tuples:  Lists that can't be changed

T = (1, 2, 3)
T[0]
#T[1] = 99 # Not allowed

# We could also say:
    
a, b, c = 1, 2, 3
print(a)
print(b)
print(c)


# How we swap values in other languages

x = 'hello'
y = 'world'
print(x, y)

temp = x
x = y
y = temp

print(x, y)

# How we swap values in python
# Lets restore x and y back to their original values 

x, y = y, x

print(x, y)

#%%
# Why tuples?
# Sometimes you want a function to return multiple values

def min_avg_max(L):
    """ Return the minimum, average, and maximum of a list """
    if len(L) == 0:
        return None
    
    minimum = min(L)
    maximum = max(L)
    average = sum(L) / len(L)
    
    return minimum, average, maximum

a, b, c = min_avg_max([1,4,6,8,5,6,3,5,4,2,3,99])
print(a,b,c)
    
        
#%% Tuples play an important role in dictionaries (LATER)

# << Coming soon >>





#%%   Lists of lists

# Lists can store anything, including other lists
# The elements don't have to be the same type

L = [1, 2, "hello", True, ['a', 'b', 'c']]

len(L)

#%% A 4 x 3 array:  3 sublists each of length 3

groceries = [['apples', 6, 0.99],
             ['milk', 1, 1.49],
             ['break', 2, 3.50]]

groceries[1]
groceries[1][0]

total_paid = 0.0


#%% Let's put it all together

def total_bill(grocery_list, sales_tax = 0.0):
    total = 0.0
    for item in range(len(grocery_list)):
        total += grocery_list[item][1] * grocery_list[item][2]
    
    # add sales tax
    total += total * (1 + sales_tax)
    return round(total, 2)

total_bill(groceries, sales_tax = 0.07)
        


#%% Two-dimensional arrays (lists within lists)

L = [[1,  2,  3,  4], 
     [5,  6,  7,  8], 
     [9, 10, 11, 12]]

L[1]
L[1][2]

L[1][2] = 99

L



#%% A resulable function to initialize an empy array
# with some default value, usually zero

def create_array(rows, cols, f=0):
    """ Create an empty 2D array
    rows = # of rows (sublists)
    cols = # of columns (size of each sublist)
    f = initializing function f(i,j) or numeric constant
    """
    
    L = []
    for i in range(rows):
        L.append([])
        for j in range(cols):
            if type(f) in [int, float]:
                L[i].append(f)
            else:
                L[i].append(f(i,j))
    return L


my_array = create_array(3, 1, f=-1)
print(my_array)


def get_size(L):
    """ Return the dimensions (rows x col) of the array
    L - A 2D array (list of lists)
    """
    rows = len(L)
    if rows > 0:
        cols = len(L[0])
    else:
        cols = 0
    
    return rows, cols


print(get_size(my_array))


#%% Print array

def print_array(L):
    for row in L:
        print(row)
    
    
        
#%% A multiplication table
# True story: in Vermont they only teach you up to 10x10.
# Don't ask me what 12x8 is.  I have no idea.  Kidding I know.
# But I have to think about it.....

# Create a 13 x 13 table.   
# 13 lists each containing 13 elements


def mult(i,j):
    return i * j




MT = create_array(13,13, f=mult)
      
print_array(MT)  
print(MT[12][9])
    
    
#%% Cool patterns

# Create a 500 x 500 table.   
# 13 lists each containing 13 elements

ROWS = 500
COLS = 500


def func(x,y):
    """ User-defined function f(x,y) """
    return (x**2 + y**2) % 107

def weight(x,y):
    """ The weight of binary numbers """
    return bin(x*y).count('1') % 15

    
pat = create_array(ROWS, COLS, f=func)



import matplotlib.pyplot as plt
plt.figure(figsize=(10,10), dpi=100)
plt.imshow(pat) #, cmap='Spectral')
plt.savefig('pattern.png')

   




