#Chapter 1 - Foundations for efficiencies


#A taste of things to come
# Print the list created using the Non-Pythonic approach
names = ['Jerry', 'Kramer', 'Elaine', 'George', 'Newman']
i = 0
new_list = []
while i < len(names):
    if len(names[i]) >= 6:
        new_list.append(names[i])
    i += 1
print(new_list)
# Print the list created by looping over the contents of names
better_list = []
for name in names:
    if len(name) >= 6:
        better_list.append(name)
print(better_list)
# Print the list created by using list comprehension
best_list = [name for name in names if len(name) >= 6]
print(best_list)
print("=========================================================")


#Built-in practice: range()
# Create a range object that goes from 0 to 5
nums = range(6)
print(type(nums))

# Convert nums to a list
nums_list = list(nums)
print(nums_list)

# Create a new list of odd numbers from 1 to 11 by unpacking a range object
nums_list2 = [*range(1,12,2)]
print(nums_list2)
print("=========================================================")


#Built-in practice: enumerate()
# Rewrite the for loop to use enumerate
names = ['Jerry', 'Kramer', 'Elaine', 'George', 'Newman']
indexed_names = []
for i,name in enumerate(names):
    index_name = (i,name)
    indexed_names.append(index_name)
print(indexed_names)

# Rewrite the above for loop using list comprehension
indexed_names_comp = [(i,name) for i,name in enumerate(names)]
print(indexed_names_comp)

# Unpack an enumerate object with a starting index of one
indexed_names_unpack = [*enumerate(names, 1)]
print(indexed_names_unpack)
print("=========================================================")


#Built-in practice: map()
names = ['Jerry', 'Kramer', 'Elaine', 'George', 'Newman']
# Use map to apply str.upper to each element in names
names_map  = map(lambda name: str.upper(name), names)

# Print the type of the names_map
print(type(names_map))

# Unpack names_map into a list
names_uppercase = [*names_map]

# Print the list created above
print(names_uppercase)
print("=========================================================")


#Practice with NumPy arrays
# Print second row of nums
import numpy as np

nums = np.array([[1, 2, 3, 4, 5],[6, 7, 8, 9, 10]])

print(nums[1,:])

# Print all elements of nums that are greater than six
print(nums[nums > 6])

# Double every element of nums
nums_dbl = nums * 2
print(nums_dbl)

# Replace the third column of nums
nums[:,2] = nums[:,2] + 1
print(nums)
print("=========================================================")


#Bringing it all together: Festivus!
# Create a list of arrival times
arrival_times = [*range(10, 60, 10)]
print(arrival_times)

# Create a list of arrival times
arrival_times = [*range(10,60,10)]

# Convert arrival_times to an array and update the times
arrival_times_np = np.array(arrival_times)
new_times = arrival_times_np - 3
print(new_times)

# Create a list of arrival times
arrival_times = [*range(10,60,10)]

# Convert arrival_times to an array and update the times
arrival_times_np = np.array(arrival_times)
new_times = arrival_times_np - 3

# Use list comprehension and enumerate to pair guests to new times
names = ['Jerry', 'Kramer', 'Elaine', 'George', 'Newman']
guest_arrivals = [(names[i],time) for i,time in enumerate(new_times)]
print(guest_arrivals)

# Create a list of arrival times
arrival_times = [*range(10,60,10)]

# Convert arrival_times to an array and update the times
arrival_times_np = np.array(arrival_times)
new_times = arrival_times_np - 3

# Use list comprehension and enumerate to pair guests to new times
guest_arrivals = [(names[i],time) for i,time in enumerate(new_times)]

# Map the welcome_guest function to each (guest,time) pair
welcome_map = map(welcome_guest, guest_arrivals)

guest_welcomes = [*welcome_map]
print(*guest_welcomes, sep='\n')

print("=========================================================")