Today: TK GUI drawing, lambda/def, map-lambda, custom sorting with lambda
Suppose I ask you to compute a new list, doubling each number
result = []
for num in nums:
result.append(num * 2)
return result
Now I want one where each number is times -1
result = []
for num in nums:
result.append(num * -1)
return result
Now I want one where each number is plus 100
result = []
for num in nums:
result.append(num + 100)
return result
>>> list(map(lambda num: num * 2, nums)) [2, 4, 6, 8] >>> list(map(lambda num: num * -1, nums)) [-1, -2, -3, -4] >>> list(map(lambda num: num + 100, nums)) [101, 102, 103, 104]
The code of a def can be used instead of a lambda, like this:
>>> nums = [1, 2, 3, 4] >>> >>> list(map(lambda num: num * 2, nums)) # lambda [2, 4, 6, 8] >>> >>> >>> def double(n): # do it as a def ... return n * 2 ... >>> list(map(double, nums)) # specify "double", no parens! [2, 4, 6, 8]
Where we would put a lambda, just put the name of the function. This is the rare case of referring to a function by name, but not putting () after it. The () calls the function, but here we want to identify the function by name but not call it.
If the code you want is several lines long, expressing it in a def is a better approach. Lambda's are best for truly short bits of code.
Next step: I need to show you a context where this ability to spec little bits of code is useful. We'll do that next.
>>> foods = [('radish', 2, 8), ('donut', 10, 1), ('apple', 7, 9), ('broccoli', 6, 10)]
>>>
>>> sorted(foods)
[('apple', 7, 9), ('broccoli', 6, 10), ('donut', 10, 1), ('radish', 2, 8)]
>>>
[('radish', 2, 8), ('donut', 10, 1), ('apple', 7, 9), ('broccoli', 6, 10)]
# Project out these values for sort-compare
[2, 10, 7, 6]
lambda food: food[1]
Q: What is the parameter to the lambda?
A: One elem from the list (similar to map)
>>> foods = [('radish', 2, 8), ('donut', 10, 1), ('apple', 7, 9), ('broccoli', 6, 10)]
>>> # sort by tasty - project out the tasty int - radish first, donut last
>>> sorted(foods, key=lambda food: food[1])
[('radish', 2, 8), ('broccoli', 6, 10), ('apple', 7, 9), ('donut', 10, 1)]
>>>
>>> sorted(foods, key=lambda food: food[1], reverse=True) # by tasty, reverse=True
[('donut', 10, 1), ('apple', 7, 9), ('broccoli', 6, 10), ('radish', 2, 8)]
>>>
>>> sorted(foods, key=lambda food: food[2], reverse=True) # by healthy
[('broccoli', 6, 10), ('apple', 7, 9), ('radish', 2, 8), ('donut', 10, 1)]
>>>
>>> sorted(foods, key=lambda food: food[1] * food[2], reverse=True) # by tasty*healthy
[('apple', 7, 9), ('broccoli', 6, 10), ('radish', 2, 8), ('donut', 10, 1)]
>>>
>>> foods = [('radish', 2, 8), ('donut', 10, 1), ('apple', 7, 9), ('broccoli', 6, 10)]
>>> max(foods) # uses [0] by default - tragic!
('radish', 2, 8)
>>>
>>> sorted(foods, key=lambda food: food[1])
[('radish', 2, 8), ('broccoli', 6, 10), ('apple', 7, 9), ('donut', 10, 1)]
>>>
>>> max(foods, key=lambda food: food[1])
('donut', 10, 1)
>>> min(foods, key=lambda food: food[1])
('radish', 2, 8)
-Pulling out one element is much faster than sorting all n elements
>>> strs = ['coffee', 'Donut', 'Zebra', 'apple', 'Banana'] >>> sorted(strs) ['Banana', 'Donut', 'Zebra', 'apple', 'coffee']
>>> strs = ['coffee', 'Donut', 'Zebra', 'apple', 'Banana'] >>> >>> sorted(strs, key=lambda s: s.lower()) # not case sensitive ['apple', 'Banana', 'coffee', 'Donut', 'Zebra'] >>> >>> sorted(strs, key=lambda s: s[len(s)-1]) # by last char ['Zebra', 'Banana', 'coffee', 'apple', 'Donut'] >>>
A common case is that your load up a dict with your data. Then use sorted() on d.items() to order the output the way you want.
>>> items = [('z', 1), ('a', 3), ('e', 11), ('b', 3), ('c', 2)]
>>> items = [('z', 1), ('a', 3), ('e', 11), ('b', 3), ('c', 2)]
>>>
>>> sorted(items)
[('a', 3), ('b', 3), ('c', 2), ('e', 11), ('z', 1)]
>>>
>>> sorted(items, key=lambda pair: pair[1]) # project out pair[1]
[('z', 1), ('c', 2), ('a', 3), ('b', 3), ('e', 11)]
>>>
>>> sorted(items, key=lambda pair: pair[1], reverse=True)
[('e', 11), ('a', 3), ('b', 3), ('c', 2), ('z', 1)]
>>>
>>> max(items, key=lambda pair: pair[1])
('e', 11)
This is a version of our earlier wordcount example, but modified to take a "-top" command line argument like this, which lists the N most common words in a text
$ python3 wordcount.py poem.txt are 2 blue 2 red 2 roses 1 violets 1 $ $ python3 wordcount-solution.py -top 10 alice-book.txt the 1639 and 866 to 725 a 631 she 541 it 530 of 511 said 462 i 410 alice 386
print_top() Solution Code
def print_top(counts, n):
"""
Given counts dict and int N, print the N most common words
in decreasing order of count
the 1045
a 672
...
"""
items = counts.items()
# Could print the items in raw form, just to see what we have
#print(items)
pass
# Your code - my solution is 3 lines long, but it's dense!
# Sort the items with a lambda so the most common words are first.
# Then print just the first N word,count pairs with a slice
items = sorted(items, key=lambda pair: pair[1], reverse=True) # 1. Sort largest count first
for word, count in items[:n]: # 2. Slice to grab first N
print(word, count)