
# We will also occasionally use map, reduce, and filter, which provide 
# functional alternatives to list comprehensions:

def double(x):
    return 2 * x

xs = [1, 2, 3, 4]
print(xs)

# Double elements in LIST using list comprehension
twice_xs = [double(x) for x in xs] 		# [2, 4, 6, 8]

print(twice_xs)

# Distribute the double function over a LIST with map():
twice_xs = map( double, xs )

# This is a "map object", to print it, construct a LIST with list() constructor:

print(list(twice_xs))


# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# We can use functools.partial to create a function that doubles an input list
# like this:
# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

import functools

list_doubler =  functools.partial( map, double ) # list_doubler(x) ~= map(double, x)

twice_xs = list_doubler(xs)
print(list(twice_xs))


# $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
# map() can make multiple-argument functions if you provide multiple lists:
# $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$

# multiple has 2 arguments
def multiply(x, y): return x * y

products = map(multiply, [1, 2], [4, 5])  # ==>  [ multiple(1,4),  multiple(2,5) ]

print(list(products) )
