{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# 8.2 List Comprehensions & Higher order functions\n",
"\n",
"\n",
"## Topics\n",
"- list shortcuts\n",
"- lambda functions applications\n",
"- built-in higher order functions\n",
"\n",
"## 8.2.1 List comprehension\n",
"- list is a very powerful and commonly used container\n",
"- list shortcuts can make you an efficient programmer\n",
"- E.g., an arithmetic set $S = \\{x^2 : x \\in \\{0 ... 9\\}\\}$\n",
" - is equivalent to: \n",
" ```python\n",
" S = [x**2 for x in range(10)]\n",
" ```\n",
"- consists of brackets containing an expression followed by a for clause, then zero or more for or if clauses\n",
" - the expressions can be anything\n",
" - always results a new list from evaluating expression\n",
"- syntax:\n",
"```python\n",
"somelist = [expression for item in list if conditional]\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"# Typical way to create a list of squared values of list 0 to 9?\n",
"sq = []\n",
"for i in range(10):\n",
" sq.append(i**2)"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]\n"
]
}
],
"source": [
"print(sq)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"# List comprehension -- handy technique:\n",
"S = [x**2 for x in range(10)]"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"S"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In maths: V = (1, 2, 4, 8, ... 2 12)"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096]\n"
]
}
],
"source": [
"# In python ?:\n",
"V = [2**x for x in range(13)]\n",
"print(V)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In mathematics: $M = \\{x | x \\in S \\ and \\ x \\ even\\}$"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"# Simple approach\n",
"M = []\n",
"for x in S:\n",
" if x%2 == 0:\n",
" M.append(x)"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[0, 4, 16, 36, 64]\n"
]
}
],
"source": [
"print(M)"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
"# List comprehension\n",
"M1 = [x for x in S if x%2==0]"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [],
"source": [
"assert M == M1, 'M and M1 are not equal!'"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
"#sentence = \"The quick brown fox jumps over the lazy dog\"\n",
"#words = sentence.split()\n",
"# can make a list of tuples or list of lists\n",
"wlist = [(w.upper(), w.lower(), len(w)) for w in \"The quick brown fox jumps over the lazy dog\".split()]"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[('THE', 'the', 3),\n",
" ('QUICK', 'quick', 5),\n",
" ('BROWN', 'brown', 5),\n",
" ('FOX', 'fox', 3),\n",
" ('JUMPS', 'jumps', 5),\n",
" ('OVER', 'over', 4),\n",
" ('THE', 'the', 3),\n",
" ('LAZY', 'lazy', 4),\n",
" ('DOG', 'dog', 3)]"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"wlist"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 8.2.2 higher order functions and lambda applications\n",
"- map, reduce, filter, sorted functions take function and iterable such as list as arguments\n",
"- lambda expression can be used as a parameter for higher order functions"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### sorted( )"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"list1 = ['Apple', 'apple', 'ball', 'Ball', 'cat']\n",
"list2 = sorted(list1, key=lambda x: x.lower())"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"['Apple', 'apple', 'ball', 'Ball', 'cat']\n"
]
}
],
"source": [
"print(list2) "
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"list3 = [('cat', 10), ('ball', 20), ('apple', 3)] \n",
"from operator import itemgetter\n",
"list5 = sorted(list3, key=itemgetter(1), reverse=True)"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[('ball', 20), ('cat', 10), ('apple', 3)]\n"
]
}
],
"source": [
"print(list5)"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"list6 = sorted(list3, key=lambda x: x[1], reverse=True)"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[('ball', 20), ('cat', 10), ('apple', 3)]\n"
]
}
],
"source": [
"print(list6)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### filter( )\n",
"- filter elemets in the list by returning a new list for each element the function returns True"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Help on class filter in module builtins:\n",
"\n",
"class filter(object)\n",
" | filter(function or None, iterable) --> filter object\n",
" | \n",
" | Return an iterator yielding those items of iterable for which function(item)\n",
" | is true. If function is None, return the items that are true.\n",
" | \n",
" | Methods defined here:\n",
" | \n",
" | __getattribute__(self, name, /)\n",
" | Return getattr(self, name).\n",
" | \n",
" | __iter__(self, /)\n",
" | Implement iter(self).\n",
" | \n",
" | __new__(*args, **kwargs) from builtins.type\n",
" | Create and return a new object. See help(type) for accurate signature.\n",
" | \n",
" | __next__(self, /)\n",
" | Implement next(self).\n",
" | \n",
" | __reduce__(...)\n",
" | Return state information for pickling.\n",
"\n"
]
}
],
"source": [
"help(filter)"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [],
"source": [
"list7 = [2, 18, 9, 22, 17, 24, 8, 12, 27]\n",
"list8 = list(filter(lambda x: x%3==0, list7))"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[18, 9, 24, 12, 27]\n"
]
}
],
"source": [
"print(list8)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### map( )"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Help on class map in module builtins:\n",
"\n",
"class map(object)\n",
" | map(func, *iterables) --> map object\n",
" | \n",
" | Make an iterator that computes the function using arguments from\n",
" | each of the iterables. Stops when the shortest iterable is exhausted.\n",
" | \n",
" | Methods defined here:\n",
" | \n",
" | __getattribute__(self, name, /)\n",
" | Return getattr(self, name).\n",
" | \n",
" | __iter__(self, /)\n",
" | Implement iter(self).\n",
" | \n",
" | __new__(*args, **kwargs) from builtins.type\n",
" | Create and return a new object. See help(type) for accurate signature.\n",
" | \n",
" | __next__(self, /)\n",
" | Implement next(self).\n",
" | \n",
" | __reduce__(...)\n",
" | Return state information for pickling.\n",
"\n"
]
}
],
"source": [
"help(map)"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [],
"source": [
"items = list(range(1, 11))\n",
"squared = list(map(lambda x: x**2, items))"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]\n"
]
}
],
"source": [
"print(squared)"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"# map each words with its length\n",
"sentence = \"The quick brown fox jumps over the lazy dog\"\n",
"words = [word.lower() for word in sentence.split()]"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"['the', 'quick', 'fox', 'jumps', 'over', 'the', 'lazy', 'dog']\n"
]
}
],
"source": [
"print(words)"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [],
"source": [
"w_len = list(map(lambda w: (w, w.upper(), len(w)), words))"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[('the', 'THE', 3), ('quick', 'QUICK', 5), ('fox', 'FOX', 3), ('jumps', 'JUMPS', 5), ('over', 'OVER', 4), ('the', 'THE', 3), ('lazy', 'LAZY', 4), ('dog', 'DOG', 3)]\n"
]
}
],
"source": [
"print(w_len)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### reduce( )\n",
"- reduce() is found in functools module\n",
"- used to reduce a list of values to a single output"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Help on module functools:\n",
"\n",
"NAME\n",
" functools - functools.py - Tools for working with functions and callable objects\n",
"\n",
"MODULE REFERENCE\n",
" https://docs.python.org/3.6/library/functools\n",
" \n",
" The following documentation is automatically generated from the Python\n",
" source files. It may be incomplete, incorrect or include features that\n",
" are considered implementation detail and may vary between Python\n",
" implementations. When in doubt, consult the module reference at the\n",
" location listed above.\n",
"\n",
"CLASSES\n",
" builtins.object\n",
" partial\n",
" partialmethod\n",
" \n",
" class partial(builtins.object)\n",
" | partial(func, *args, **keywords) - new function with partial application\n",
" | of the given arguments and keywords.\n",
" | \n",
" | Methods defined here:\n",
" | \n",
" | __call__(self, /, *args, **kwargs)\n",
" | Call self as a function.\n",
" | \n",
" | __delattr__(self, name, /)\n",
" | Implement delattr(self, name).\n",
" | \n",
" | __getattribute__(self, name, /)\n",
" | Return getattr(self, name).\n",
" | \n",
" | __new__(*args, **kwargs) from builtins.type\n",
" | Create and return a new object. See help(type) for accurate signature.\n",
" | \n",
" | __reduce__(...)\n",
" | helper for pickle\n",
" | \n",
" | __repr__(self, /)\n",
" | Return repr(self).\n",
" | \n",
" | __setattr__(self, name, value, /)\n",
" | Implement setattr(self, name, value).\n",
" | \n",
" | __setstate__(...)\n",
" | \n",
" | ----------------------------------------------------------------------\n",
" | Data descriptors defined here:\n",
" | \n",
" | __dict__\n",
" | \n",
" | args\n",
" | tuple of arguments to future partial calls\n",
" | \n",
" | func\n",
" | function object to use in future partial calls\n",
" | \n",
" | keywords\n",
" | dictionary of keyword arguments to future partial calls\n",
" \n",
" class partialmethod(builtins.object)\n",
" | Method descriptor with partial application of the given arguments\n",
" | and keywords.\n",
" | \n",
" | Supports wrapping existing descriptors and handles non-descriptor\n",
" | callables as instance methods.\n",
" | \n",
" | Methods defined here:\n",
" | \n",
" | __get__(self, obj, cls)\n",
" | \n",
" | __init__(self, func, *args, **keywords)\n",
" | Initialize self. See help(type(self)) for accurate signature.\n",
" | \n",
" | __repr__(self)\n",
" | Return repr(self).\n",
" | \n",
" | ----------------------------------------------------------------------\n",
" | Data descriptors defined here:\n",
" | \n",
" | __dict__\n",
" | dictionary for instance variables (if defined)\n",
" | \n",
" | __isabstractmethod__\n",
" | \n",
" | __weakref__\n",
" | list of weak references to the object (if defined)\n",
"\n",
"FUNCTIONS\n",
" cmp_to_key(...)\n",
" Convert a cmp= function into a key= function.\n",
" \n",
" lru_cache(maxsize=128, typed=False)\n",
" Least-recently-used cache decorator.\n",
" \n",
" If *maxsize* is set to None, the LRU features are disabled and the cache\n",
" can grow without bound.\n",
" \n",
" If *typed* is True, arguments of different types will be cached separately.\n",
" For example, f(3.0) and f(3) will be treated as distinct calls with\n",
" distinct results.\n",
" \n",
" Arguments to the cached function must be hashable.\n",
" \n",
" View the cache statistics named tuple (hits, misses, maxsize, currsize)\n",
" with f.cache_info(). Clear the cache and statistics with f.cache_clear().\n",
" Access the underlying function with f.__wrapped__.\n",
" \n",
" See: http://en.wikipedia.org/wiki/Cache_algorithms#Least_Recently_Used\n",
" \n",
" reduce(...)\n",
" reduce(function, sequence[, initial]) -> value\n",
" \n",
" Apply a function of two arguments cumulatively to the items of a sequence,\n",
" from left to right, so as to reduce the sequence to a single value.\n",
" For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates\n",
" ((((1+2)+3)+4)+5). If initial is present, it is placed before the items\n",
" of the sequence in the calculation, and serves as a default when the\n",
" sequence is empty.\n",
" \n",
" singledispatch(func)\n",
" Single-dispatch generic function decorator.\n",
" \n",
" Transforms a function into a generic function, which can have different\n",
" behaviours depending upon the type of its first argument. The decorated\n",
" function acts as the default implementation, and additional\n",
" implementations can be registered using the register() attribute of the\n",
" generic function.\n",
" \n",
" total_ordering(cls)\n",
" Class decorator that fills in missing ordering methods\n",
" \n",
" update_wrapper(wrapper, wrapped, assigned=('__module__', '__name__', '__qualname__', '__doc__', '__annotations__'), updated=('__dict__',))\n",
" Update a wrapper function to look like the wrapped function\n",
" \n",
" wrapper is the function to be updated\n",
" wrapped is the original function\n",
" assigned is a tuple naming the attributes assigned directly\n",
" from the wrapped function to the wrapper function (defaults to\n",
" functools.WRAPPER_ASSIGNMENTS)\n",
" updated is a tuple naming the attributes of the wrapper that\n",
" are updated with the corresponding attribute from the wrapped\n",
" function (defaults to functools.WRAPPER_UPDATES)\n",
" \n",
" wraps(wrapped, assigned=('__module__', '__name__', '__qualname__', '__doc__', '__annotations__'), updated=('__dict__',))\n",
" Decorator factory to apply update_wrapper() to a wrapper function\n",
" \n",
" Returns a decorator that invokes update_wrapper() with the decorated\n",
" function as the wrapper argument and the arguments to wraps() as the\n",
" remaining arguments. Default arguments are as for update_wrapper().\n",
" This is a convenience function to simplify applying partial() to\n",
" update_wrapper().\n",
"\n",
"DATA\n",
" WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__qualname__', '__do...\n",
" WRAPPER_UPDATES = ('__dict__',)\n",
" __all__ = ['update_wrapper', 'wraps', 'WRAPPER_ASSIGNMENTS', 'WRAPPER_...\n",
"\n",
"FILE\n",
" /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/functools.py\n",
"\n",
"\n"
]
}
],
"source": [
"import functools\n",
"help(functools)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 8.2.3 higher order function applications\n",
"\n",
"### find sum of first n values"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [],
"source": [
"s = functools.reduce(lambda x,y:x+y, range(1, 11))"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [],
"source": [
"assert sum(range(1, 11)) == s"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### find factorial (or product of) first n values"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {},
"outputs": [],
"source": [
"fact = functools.reduce(lambda x,y:x*y, range(1, 11))"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"3628800"
]
},
"execution_count": 27,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"fact"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [],
"source": [
"import math\n",
"assert math.factorial(10) == fact"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.3"
}
},
"nbformat": 4,
"nbformat_minor": 2
}