<jupyter_start><jupyter_text>Week 2 - Flow Control  The following play critical roles:  1. Indentation - running blocks of code.2. Time Delays - pacing the speed of our code.3. For Loops - iterating through data4. For Loops through multiple but related lists5. For Loops through Dictionaries6. Conditional Statements  1. Indentation* Python is unique in requiring indentations.* Indentations signify the start and end of code that belongs together (code blocks).* Without proper indentation, your code won't do what you expect.* Not working as expected? Check if you have indented correctly!  Basic Flow Example: A Counter<jupyter_code>## Using a While loop build a counter that counts from 1 to 5.
## Print the counter numbers in statement that reads "The count is" whatever the count is.
## Once it reaches 5, it should print "Done counting to 5!"

count = 1
while count <=5:
    print(f"The count is {count}")
    count = count +1
print("done counting to 5")<jupyter_output>The count is 1
The count is 2
The count is 3
The count is 4
The count is 5
done counting to 5<jupyter_text>You just controlled flow using indentation and a while loop.     How fast does our code run?<jupyter_code>import datetime as dt

counter = 1
while counter <6:
    current = dt.datetime.now() # the exact current time
    print(f"The count is {counter} and this process ran at {current}")
#     counter = counter + 1
    counter += 1
print("Done printing to 5")<jupyter_output>The count is 1 and this process ran at 2021-09-13 13:59:17.292169
The count is 2 and this process ran at 2021-09-13 13:59:17.292419
The count is 3 and this process ran at 2021-09-13 13:59:17.292441
The count is 4 and this process ran at 2021-09-13 13:59:17.292453
The count is 5 and this process ran at 2021-09-13 13:59:17.292464
Done printing to 5<jupyter_text>2. Time Delays**Delay timers** are critical when scraping data from websites for several reasons. The **two** most important reasons are:1. Sometimes your scraper clicks on links and must wait for the content to actually populated on the new page. Your script is likely to run faster than a page can load.2. You don't want your scraper to be mistaken for a hostile attack on a server. You have to slow down the scrapes.  Step 1 - Import required libraries<jupyter_code>import time # time is required. we will use its sleep function
# import datetime as dt ## we already imported this earlier, but you'd need it if starting fresh<jupyter_output><empty_output><jupyter_text>Let's add a 5-second delay:<jupyter_code>counter = 1
while counter <6:
    current = dt.datetime.now() # the exact current time
    print(f"The count is {counter} and this process ran at {current}")
#     counter = counter + 1
    counter += 1
    time.sleep(5)
print("Done printing to 5")<jupyter_output>The count is 1 and this process ran at 2021-09-13 14:04:38.373754
The count is 2 and this process ran at 2021-09-13 14:04:43.378471
The count is 3 and this process ran at 2021-09-13 14:04:48.382150
The count is 4 and this process ran at 2021-09-13 14:04:53.387505
The count is 5 and this process ran at 2021-09-13 14:04:58.392683
Done printing to 5<jupyter_text>RandomizeSoftware that tracks traffic to a server might grow suspicious about a hit every nth seconds.Let's **randomize** the time between hits by using ```randint``` from the ```random``` library.You might sometimes see me use ```randrange``` from the ```random``` library: ``` from random import randrange```. What's the difference?**Difference 1**```randrange``` is exclusive of the final range value.```randint``` is inclusive of the final range value.**Difference 2**```randrange``` allows you to add a step: ```randrange(start, end, step)``````randint ``` only has start and end: ```randint(start, end)<jupyter_code>from random import randint # import necessary library

randint(0,10)
from random import randrange ## import necessary library
randrange(0, 10)
# we've already imported random
counter = 1
while counter <6:
    
    mysnoozer = randint(4, 10)
    current = dt.datetime.now() # the exact current time
    print(f"The count is {counter} and this process ran at {current}.\
    snooze for {mysnoozer} seconds!")
    counter += 1
    
    time.sleep(mysnoozer)
print("Done printing to 5")
pip install icecream
from icecream import ic
rent = 1000
food = 400
expenses = rent + food
print(f"the total expenses is: {expenses} and rent is {rent} and food is {food} ")
ic(rent)
ic(expenses)<jupyter_output>ic| expenses: 1400<jupyter_text>3. For Loops For Loops are your best friend - most used Python expression for journalists: Iterate over:* data stored in a list and run some calculation on each value;* a list of URLs and visit each site to scrape data;* data stored in dictionary keys and values and return what you are looking for.  A simple ```for loop``` example:             Let's take **For Loops** for test drive:<jupyter_code>## RUN THIS CELL - Use this list of CEO salaries from 1985 
ceo_salaries_1985 = [150_000, 201_000, 110_000, 75_000, 92_000, 55_000]
ceo_salaries_1985
## Print each salary with in the following format:
## "A CEO earned [some value] in 1985."
for each_salary in ceo_salaries_1985:
    print(f"A ceo earned ${each_salary:,} in 1985")
## Now update each salary to 2019 dollars.
## Print the following info:
## "A CEO's salary of [1985 salary] in 1985 is worth [updated salary] in 2019 dollars."
## The CPI for 1985 is 107.6
## The 2019 CPI is 255.657
## The formula is: updated_salary = (oldSalary/oldCPI) * currentCPI
salaries_2019 = []
old_salary = [150_000, 201_000, 110_000, 75_000, 92_000, 55_000]
for ceo in old_salary:
    updated_salary = (ceo/107.6) * 255.657
    print(f"A CEO's salary of ${ceo:,} in 1985 is worth ${updated_salary:,.0f}\
    in 2019 dollars.")
    salaries_2019.append(updated_salary)
salaries_2019
ceo_salaries_1985
sals_2019 = [(salary/107.6) * 255.657 for salary in ceo_salaries_1985]
sals_2019<jupyter_output><empty_output><jupyter_text>4. For Loops through multiple but related lists<jupyter_code>##  RUN THIS CELL - You scrape a site and each datapoint is stored in different lists
first_names = ["Irene", "Ursula", "Elon", "Tim"]
last_names = ["Rosenfeld", "Burns", "Musk", "Cook"]
titles = ["Chairman and CEO", "Chairman and CEO", "CEO", "CEO"]
companies = ["Kraft Foods", "Xerox", "Tesla", "Apple"]
industries = ["Food and Beverage", "Process and Document Management", "Auto Manufacturing", "Consumer Technology"]<jupyter_output><empty_output><jupyter_text>Use ```zip()``` to zip lists together<jupyter_code>## with zip
## also print what each type of data is.

ceo_list = []
for item in zip(first_names, last_names, titles, companies, industries):
    print(item)
    print(type(item))
    ceo_list.append(item)
    
item
ceo_list
## zip it and store in a list called ceo_list


## export to a pandas dataframe
import pandas as pd
df = pd.DataFrame(ceo_list)
df.columns =["first_name", "last_name", "title", "company", "industry"]
df
## export to a csv
filename = "ceo_bios.csv"
df.to_csv(filename, index = False, encoding ="UTF-8")
## recall that dictionaries are like columns and rows in a csv
## let's turn this csv into a dataframe
pd.read_csv("ceo_bios.csv")<jupyter_output><empty_output><jupyter_text>Turn tuples into lists<jupyter_code>## zip lists into a list of lists
ceo_list = []
for item in zip(first_names, last_names, titles, companies, industries):
    print(list(item))
    print(type(list(item)))
    ceo_list.append(list(item))<jupyter_output>['Irene', 'Rosenfeld', 'Chairman and CEO', 'Kraft Foods', 'Food and Beverage']
<class 'list'>
['Ursula', 'Burns', 'Chairman and CEO', 'Xerox', 'Process and Document Management']
<class 'list'>
['Elon', 'Musk', 'CEO', 'Tesla', 'Auto Manufacturing']
<class 'list'>
['Tim', 'Cook', 'CEO', 'Apple', 'Consumer Technology']
<class 'list'><jupyter_text>5. For Loops through Dictionaries<jupyter_code>## You have a list of CEO salaries from 1969.
sals_1969 = [47_000, 65_000, 39_000, 96_000]
sals_1969
## We need the value of these salaries updated for every decade till 2019
## Here are the CPIs for each decade in list of dictionaries from 1969 to 2019.

decades_cpi = [
   {"year": 1979, "cpi": 72.6,},
    {"year": 1989, "cpi": 124}, 
    {"year": 1999, "cpi": 166.6},
    {"year": 2009, "cpi": 214.537},
    {"year": 2019, "cpi": 255.657}
              ]

## Show the contents of this list of dictionaries
decades_cpi
## What datatype is decades_cpi
type(decades_cpi)
# Check what type of data each list item is within decades_cpi

for item in decades_cpi:
    print(type(item))
## Print out each value in this format:
## "key --> value"
decades_cpi[0]
for decade in decades_cpi:
#     print(decade)
    for key, value in decade.items():
        print(f"{key} ---->{value}")
    print("********")
value<jupyter_output><empty_output><jupyter_text>The key alternates between the strings "year" and "cpi" in this loop. How do we actually target the values for "year" and "cpi" and place them in our calculations?<jupyter_code>## show it here:

for decade in decades_cpi:
    that_year = decade.get("year")
    old_cpi = decade.get("cpi")
    print(old_cpi)
old_cpi
sals_1969
## Loop through each salary and update its value for each decade
sals_1969

updated_sals = []
   
cpi_69 = 36.7
## iterate through list of salaries with for loop
for salary in sals_1969:
    
#     ic(salary)
    
 ## iterate through list of dictionaries to retrive year and old cpi
    for decade in decades_cpi:
         
        that_year = decade.get("year")
        old_cpi = decade.get("cpi")
#         ic(that_year)
#         ic(old_cpi)
        ## calc updated salary for that decade
        updated_salary = (salary/cpi_69) * old_cpi
#         ic(updated_salary)
        updated_sals.append(updated_salary)
len(updated_sals)
updated_sals<jupyter_output><empty_output><jupyter_text>6. Conditional Statements<jupyter_code>## create a list of 10 random numbers anywhere from -100 to 100 
##name the list numbers
import random
numbers = random.sample(range(-100, 101), 10)
numbers<jupyter_output><empty_output><jupyter_text>Create conditional statements that tell us if the last number and the penultimate number are positive or negative. Print a sentence that reads:```"The last number [what is it?] is [positive or negative] while  the penultimate number [what is it?] is [negative or positive]."```<jupyter_code>## if else statements
if numbers[-2] > 0:
    pen_status = "positive"
else: 
    pen_status = "negative"
if numbers[-1] > 0:
    last_status = "positive"
else:
    last_status = "negative"   
print(f"The last number {numbers[-1]} is {last_status} while \
 the penultimate number {numbers[-2]} is {pen_status}.")<jupyter_output>The last number -66 is negative while  the penultimate number -73 is negative.<jupyter_text>Tenary Expression```variable = value1 if some_condition else value2```<jupyter_code>## ternary expression
# as ternary expression

pen_status  = "positive" if numbers[-2] > 0 else "negative"
last_status = "positive" if numbers[-1] > 0 else "negative"
print(f"The last number {numbers[-1]} is {last_status} while \
 the penultimate number {numbers[-2]} is {pen_status}.")<jupyter_output>The last number 36 is positive while  the penultimate number -9 is negative.<jupyter_text>Multiple Tenary Expression```variable = value1 if condition1 else value2 if condition2 else value3 ```<jupyter_code>## A simple example
x, y = 10, 1
'''
write a simple if else statement that prints out x is greater than y,
or y is greater than x or if they are equal.
'''
if x > y:
    print(f"{x} is greater than {y}")
elif x < y:
    print(f"{x} is less than {y}")
else:
    print(f"{x} and {y} are equal")
## Now as a ternary
print(f"x ({x}) is greater than y ({y})" if x > y\
      else f"x ({x}) is less than y ({y})" if x < y\
      else "x and y are equal")<jupyter_output>x (10) is greater than y (1)<jupyter_text>Conditionals as Tuples```("False: Does not meet condition", "True: Meets condition")[conditional expression]```<jupyter_code>age = 20
## conditional tuple

z = ("Too young to buy alcohol legally in US!",
     "Can buy alcohol legally in the uS!")[age >= 21]
z
((f"x, {x} is less than y {y}",\
 f"x {x} is equal to y {y}",\
  f"x {x} is greater y {y}"))[[x < y, x == y, x > y].index(True)]<jupyter_output><empty_output><jupyter_text>ChallengeWrite a tenary expression to update the first conditional exercise above to deal Zeros. For example if the random list generates:```[46, 30, 31, -56, 18, 57, -90, 81, 0, 0]```It should print out:```The last number (0) is neither negative or positive at zero while the penultimate number (0) is neither negative or positive at zero.```<jupyter_code>## activate the list
numbers = [46, 30, 31, -56, 18, 57, -90, 81, 0, 0]
## write your multiple ternary expression<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11097266568024297, 'fraction_numerical': 0.05124211510007009, 'mean_word_length': 4.485689876121316, 'pattern_counts': {'":': 10, '<': 72, '<?xml version=': 0, '>': 75, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '17', 'dir': 'jupyter-structured-clean-dedup', 'id': '295729', 'license': 'MIT', 'n_tokens_mistral': 4671, 'n_tokens_neox': 4087, 'n_words': 1644, 'path': 'in-class/week-2-inclass-exercises-DEMO.ipynb', 'repo_name': 'jchapamalacara/fall21-students-practical-python', 'size': '12841'}