Skip to content

Instantly share code, notes, and snippets.

@kadams54
Last active October 2, 2023 14:16
Show Gist options
  • Save kadams54/c7c2e0e3b5855f4f5a81af2209f4c08b to your computer and use it in GitHub Desktop.
Save kadams54/c7c2e0e3b5855f4f5a81af2209f4c08b to your computer and use it in GitHub Desktop.
Grokking Simplicity: Chapter 12 Functional iteration

Python's equivalents:

  1. map()
  2. filter()
  3. functools.reduce()

Several notes:

Python uses the reverse order for the arguments for the map()/filter() defined in the book: in Python, the function comes first, then the collection.

Python has banished reduce() to the functools module; Python's creator, Guido van Rossum, finds it conceptually complex (he's not wrong). Consequently there are multiple options for doing reduce()-like behavior in Python:

  • Guido's preferred normal for loop.
  • Use functools.reduce().
  • Pull in a third party library, like pydash, which has its own reduce() implementation.

Python also has list comprehensions, which do mapping and filtering inline:

friends = [person for person in people if person.is_friend] # filters
greetings = [greet(name) for name in friends]  # maps
greetings = [greet(person.name) for person in people if person.is_friend] # maps & filters

The downside to comprehension (list and dict) is that they're not first class constructs, so they're not easily composable into a chain of operations.

# THREE WAYS TO DEFINE A FUNCTION
friends_names = ['Brian', 'Jill']
# 1. Globally defined:
def greet(name):
return "Hello, " + name
friend_greetings = map(greet, friends_names)
# friend_greetings is an iterator, so we have to use list() to see all the
# values associated with the iterator.
# >>> list(friend_greetings)
# ['Hello, Brian', 'Hello, Jill']
# 2. Locally defined:
def greet_everybody(friends_names):
def greet(name):
return "Hello, " + name
return map(greet, friends_names)
friend_greetings = greet_everybody(friends_names)
# >>> list(friend_greetings)
# ['Hello, Brian', 'Hello, Jill']
# 3. Defined inline (note that Python calls anonymous functions "lambdas";
# also note that Python inline functions are limited to a single line):
friend_greetings = map(lambda name: "Hello, " + name, friends_names)
# >>> list(friend_greetings)
# ['Hello, Brian', 'Hello, Jill']
# One piece of code we’ll need to write is useful during the holidays. We need
# to send out postcards to all of our customers. We need an object containing
# the first name, last name, and address of each customer. Using map(), write
# the code to generate this array of objects.
#
# Givens
#
# - customers is an list of all customers.
# - customer["first_name"], customer["last_name"], and customer["address"] will
# give you the data you need.
customers = [
{
"first_name": "Bilbo",
"last_name": "Baggins",
"address": "Bag End, Bagshot Row, Hobbiton, The Shire",
"favourite_colour": "green",
},
{
"first_name": "Hermoine",
"last_name": "Granger",
"address": "12 Grimmauld Place, Islington, London, UK",
"favourite_colour": "red"
},
]
def to_mailing_address(customer):
return {
"first_name": customer["first_name"],
"last_name": customer["last_name"],
"address": customer["address"],
}
from pprint import pprint # Will pretty print the results.
pprint(list(map(to_mailing_address, customers)))
# > python 02_holiday_postcards.py
# [{'address': 'Bag End, Bagshot Row, Hobbiton, The Shire',
# 'first_name': 'Bilbo',
# 'last_name': 'Baggins'},
# {'address': '12 Grimmauld Place, Islington, London, UK',
# 'first_name': 'Hermoine',
# 'last_name': 'Granger'}]
# The marketing department wants to run a small test. They want to arbitrarily
# select approximately one third of the customers and send them a different email
# from the rest. For marketing’s purposes, it is good enough to use the user’s ID
# and check if it’s divisible by 3. If it is, they’re in the test group. Your task
# is to write code to generate the test and non-test groups.
#
# Givens
#
# - customers is an array of all customers.
# - customer["id"] will give you the user’s ID.
# - % is the remainder operator; x % 3 === 0 checks if x is divisible by 3.
customers = [{"id": 1}, {"id": 2}, {"id": 3}]
test_group = filter(lambda customer: customer.id % 3 == 0, customers)
non_test_group = filter(lambda customer: customer.id % 3 != 0, customers)
from pprint import pprint
pprint(list(test_group))
pprint(list(non_test_group))
# > python 03_marketing_test.py
# [{'id': 3}]
# [{'id': 1}, {'id': 2}]
from functools import reduce
def sum(numbers):
return reduce(lambda total, n: total + n, numbers, 0)
def product(numbers):
return reduce(lambda total, n: total * n, numbers, 1)
from functools import reduce
def min(numbers):
return reduce(lambda m, n: m if m < n else n, numbers, None)
def max(numbers):
return reduce(lambda m, n: m if m > n else n, numbers, None)
from functools import reduce
def map(array, f):
return reduce(lambda ret, item: [*ret, f(item)], array, [])
def filter(array, f):
return reduce(lambda ret, item: [*ret, item] if f(item) else ret, array, [])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment