<jupyter_start><jupyter_text>Section IV. FunctionsFunctions are defined using *def*<jupyter_code>def double(x):
    """this is where you put an optional docstring
    that explains what the function does.
    for example, this function multiplies its input by 2"""
    
    return x * 2<jupyter_output><empty_output><jupyter_text>You can call a function after it is defined<jupyter_code>z = double(10) # z is 20<jupyter_output><empty_output><jupyter_text>You can give default values to parameters<jupyter_code>def my_print(message='my default message'):
    print (message)

my_print('hello') # prints 'hello'
my_print()        # prints 'my default message<jupyter_output><empty_output><jupyter_text>Sometimes it is useful to specify arguments by name<jupyter_code>def subtract(a=0, b=0):
    return a - b

subtract(10, 5)        # returns 5
subtract(0, 5)         # returns -5
subtract(b = 5)        # same as above
subtract(b = 5, a = 0) # same as above<jupyter_output><empty_output><jupyter_text>Exercise 4.1Define a function *square_root* that receives a number as a parameter and returns the quare root of that number. Determine the quare root of 6.25.<jupyter_code># Answer here<jupyter_output><empty_output><jupyter_text>Lambdas and List Comprehensions Functions are objects too<jupyter_code>def double(x): 
    return x * 2

dd = double
def apply_to_one(f):
    return f(1)

apply_to_one(dd)<jupyter_output><empty_output><jupyter_text>Small anonymous functions can be created with the *lambda* keyword<jupyter_code>def small_func(x): # Equivalent to "lambda x: x + 4"
    return x + 4

apply_to_one(small_func)
apply_to_one(lambda x: x + 4)<jupyter_output><empty_output><jupyter_text>Sorting List*sorted()* keeps the original list intact and returns a new sorted list<jupyter_code>x = [4, 1, 3, 2]
y = sorted(x)    # y is [1,2,3,4], x is unchanged<jupyter_output><empty_output><jupyter_text>*list.sort()* sort the original list<jupyter_code>x.sort()          # now x is [1,2,3,4]<jupyter_output><empty_output><jupyter_text>You can change the default behavior of sorted using lambdas<jupyter_code># sort the list by absolute value from largest to smallest 
x = [-4, 1, -2, 3]
y = sorted(x, key=abs, reverse=True)  # is [-4,3,-2,1]
grades = { # dictionary literal 
    'Jane' : 90, 
    'Nathan' : 95,
    'Kyle': 92
}

# sort the grades from highest count to lowest 
# using an anonymous function
newgrades = sorted(grades.items(), key=lambda item: item[1], reverse=True)<jupyter_output><empty_output><jupyter_text>List ComprehensionA very convenient way to create a new list<jupyter_code>squares = [x * x for x in range(5)]
# Above code is the same as...
squares = []
for x in range(5): 
    squares.append(x * x)<jupyter_output><empty_output><jupyter_text>Can also be used to filter list<jupyter_code>even_numbers = [x for x in range(5) if x % 2 == 0]
# Above code is the same as...
even_numbers = []
for x in range(5):
    if x % 2 == 0:
        even_numbers.append(x)<jupyter_output><empty_output><jupyter_text>Exercise 4.1Use a list comprehension to create a list of tuples containing the numbers 1 to 5 and their cubes -- that is, `[(1, 1), (2, 8), (3, 27), ...]`. Hint: To create tuples, palce parentheses around the expression to the left of the list comprehension's *for* clause.<jupyter_code># Answer here<jupyter_output><empty_output><jupyter_text>More complex examples<jupyter_code># create 100 pairs (0,0) (0,1) ... (9,8), (9,9) 
pairs = [(x, y) 
         for x in range(10) 
         for y in range(10)]   
# only pairs with x < y,   
# range(lo, hi) equals 
# [lo, lo + 1, ..., hi - 1] 
increasing_pairs = [(x, y)
                    for x in range(10)
                    for y in range(x + 1, 10)]<jupyter_output><empty_output><jupyter_text>map(), reduce(), filter()Convenient tools in python to apply function to sequences of data.<jupyter_code># map() applies a function to a list

a = range(5)
list(map(lambda x: 2 * x), a)
# filter() returns all values satisfying a condition 

a = range(5)
list(filter(lambda x: x % 2 == 0, a))
# reduce() combines all values using a function to generate a single result

a = range(10)
reduce(lambda x, y: x + y, a)<jupyter_output><empty_output><jupyter_text>Exercise 4.2 (Assignment)Map a list of the three Farenheit temparatures 41, 32, 212 to a list of tuples containing the Fahrenheit temparatures and their Celsius equivalents. Convert Ferenheit temperatures to Celcius tiwht the following forumla:    Celcsius = (Farenheit - 32) * (5/9)<jupyter_code># Answer here<jupyter_output><empty_output><jupyter_text>zip()Useful function to combine multiple lists into a list of tuples<jupyter_code>list(zip(['a', 'b', 'c'], [1, 2, 3], ['A', 'B', 'C']))
names = ['Nathan’, Jane’, Kyle']
grades = [100, 90, 95]
list(zip(names, grades))<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1192451265035255, 'fraction_numerical': 0.02613023641642472, 'mean_word_length': 4.64093567251462, 'pattern_counts': {'":': 0, '<': 70, '<?xml version=': 0, '>': 69, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '17', 'dir': 'jupyter-structured-clean-dedup', 'id': '566422', 'license': 'MIT', 'n_tokens_mistral': 1773, 'n_tokens_neox': 1656, 'n_words': 537, 'path': 'notebooks/4_python_functions.ipynb', 'repo_name': 'ac-analytics/python-basic-training', 'size': '4822'}