EECS 110: Lec 5: List Comprehensions Aleksandar Kuzmanovic Northwestern University http://cs.northwestern.edu/~akuzma/classes/EECS110-s09/
The building blocks of functional computing EECS 110 today The building blocks of functional computing data, sequences conditionals recursion List Comprehensions map and applications Homework 2 - this coming Sunday…! 1 lab problem Tuesday 3 problems Homework 1 - submitted 2 python problems
functional programming >>> 'fun' in 'functional' True representation via list structures (data) leverage self-similarity (recursion) create small building blocks (functions) Compose these together to solve or investigate problems. Key ideas in functional programming not maximally efficient for the computer… elegant and concise vs.
return to recursion Composing functions into specific applications Creating general functions that will be useful everywhere (or almost…)
return to recursion Composing functions into specific applications Creating general functions that will be useful everywhere (or almost…) building blocks with which to compose…
sum, range def sum(L): """ input: a list of numbers, L output: L's sum
sum, range Base Case Recursive Case def sum(L): """ input: a list of numbers, L output: L's sum """ if len(L) == 0: return 0.0 else: return L[0] + sum(L[1:]) Base Case This input to the recursive call must be "smaller" somehow… if the input has no elements, its sum is zero Recursive Case if L does have an element, add that element's value to the sum of the REST of the list…
sum, range def range(low,hi): """ input: two ints, low and hi output: int list from low up to hi """ excluding hi
sum, range def range(low,hi): """ input: two ints, low and hi output: int list from low up to hi """ if hi <= low: return [] else: return excluding hi
sum, range def range(low,hi): """ input: two ints, low and hi output: int list from low up to hi """ if hi <= low: return [] else: return [low] + range(low+1,hi) excluding hi
sum and range >>> sum(range(101)) Looks sort of scruffy for a 7-year old… ! How can you do this sum quickly? S = 1 + 2 + 3 + … + 100 + S = 100 + 99 + 98 + + 1 2S = 101 + 101 + 101 + … + 101 = 100 * 101 = 10100 S = 10100 / 2 = 5050 This approach was discovered by Gauss when he was a schoolboy. The table lists the various accounts that are given of the story of what happened in the classroom when he discovered it. http://bit-player.org/wp-content/gaussfiles/gauss-table.html and 100 more…
Recursion: Good News/Bad News Recursion is common (fundamental) in functional programming def dblList(L): """ Doubles all the values in a list. input: L, a list of numbers """ if L == []: return L else: return [L[0]*2] + dblList(L[1:]) But you can sometimes hide it away!
Map: The recursion "alternative" def dbl(x): return 2*x >>> map( dbl, [0,1,2,3,4,5] ) [0, 2, 4, 6, 8, 10] def sq(x): return x**2 >>> map( sq, range(6) ) [0, 1, 4, 9, 16, 25] (1) map always returns a list (2) map(f,L) calls f on each item in L def isana(x): return x=='a’ >>> map( isana, 'go away!' ) [0, 0, 0, 1, 0, 1, 0, 0] Hey… this looks a bit False to me!
Map ! Without map With map! def dblList(L): """ Doubles all the values in a list. input: L, a list of numbers """ if L == []: return L else: return [L[0]*2] + dblList(L[1:]) Without map def dbl(x): return x*2 def dblList(L): """ Doubles all the values in a list. input: L, a list of numbers """ return map(dbl, L) With map!
Map: a higher-order function In Python, functions can take other functions as input… def map( f, L ): Key Concept Functions ARE data!
Why use map?
Why use map? More elegant / shorter code, “functional in style” Faster execution in Python – map optimized for operations in lists Avoid rewriting list recursion (build once, use lots)
Mapping without map: List Comprehensions Anything you want to happen to each element of a list name that takes on the value of each element in turn the list (or string) any name is OK! input >>> [ dbl(x) for x in [0,1,2,3,4,5] ] [0, 2, 4, 6, 8, 10] output input >>> [ x**2 for x in range(6) ] [0, 1, 4, 9, 16, 25] output >>> [ c == 'a' for c in 'go away!' ] [0, 0, 0, 1, 0, 1, 0, 0] input output
Mapping without map: List Comprehensions def dbl(x): return 2*x >>> map( dbl, [0,1,2,3,4,5] ) [0, 2, 4, 6, 8, 10] >>> [ dbl(x) for x in [0,1,2,3,4,5] ] [0, 2, 4, 6, 8, 10] def sq(x): return x**2 >>> map( sq, range(6) ) [0, 1, 4, 9, 16, 25] >>> [ x**2 for x in range(6) ] [0, 1, 4, 9, 16, 25] >>> map( isana, 'go away!' ) [0, 0, 0, 1, 0, 1, 0, 0] def isana(x): return x=='a’ >>> [ c == 'a' for c in 'go away!' ] [0, 0, 0, 1, 0, 1, 0, 0]
implemented via raw recursion List Comprehensions def len(L): if L == []: return 0 else: return 1 + len(L[1:]) len(L) def sajak(s): if len(s) == 0: return 0 else: if s[0] not in 'aeiou': return sajak(s[1:]) return 1+sajak(s[1:]) sajak(s) def sScore(s): if len(s) == 0: return 0 else: return letScore(s[0]) + \ sScore(s[1:]) sScore(s) scrabble score implemented via raw recursion
List Comprehensions len(L) LC = [1 for x in L] return sum( LC ) sScore for exam?
List Comprehensions len(L) sajak(s) LC = [1 for x in L] return sum( LC ) sajak(s) # of vowels LC = [c in 'aeiou' for c in s] return sum( LC ) sScore for exam?
List Comprehensions len(L) sajak(s) sScore(s) LC = [1 for x in L] return sum( LC ) sajak(s) # of vowels LC = [c in 'aeiou' for c in s] return sum( LC ) sScore for exam? sScore(s) scrabble score LC = [ letScore(c) for c in s] return sum( LC )
Quiz Write each of these functions concisely using list comprehensions… Name(s): Write input: e, any element L, any list or string Remember True == 1 and False == 0 def count(e,L): output: the # of times L contains e example: count('f', 'fluff') == 3 W are the winning numbers Write input: Y and W, two lists of lottery numbers (ints) Y are your numbers def lotto(Y,W): output: the # of matches between Y & W example: lotto([5,7,42,44],[3,5,7,44]) == 3 Extra! Write input: N, an int >= 2 output: the number of positive divisors of N def divs(N): example: divs(12) == 6 (1,2,3,4,6,12)
Quiz sScore for exam?
Quiz count(e,L) LC = [x==e for x in L] return sum( LC ) sScore for exam?
Quiz lotto(Y,W) LC = [c in Y for c in W] return sum( LC ) sScore for exam?
Quiz divs(N) LC = [ N%c==0 for c in range(1,N+1)] return sum( LC ) sScore for exam? divs(N) LC = [ N%c==0 for c in range(1,N+1)] return sum( LC )
Quiz count(e,L) lotto(Y,W) divs(N) LC = [x==e for x in L] return sum( LC ) lotto(Y,W) LC = [c in Y for c in W] return sum( LC ) sScore for exam? divs(N) LC = [ N%c==0 for c in range(1,N+1)] return sum( LC )
See you at Lab!