{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# 8.2 List Comprehensions & Higher order functions\n", "\"Open\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 }