Python - Standard Library Flashcards

1
Q

How to efficiently add / modify / retrieve an item that may or may not be in a dictionary?

Imagine you have a dictionary named cowboy, and you want to get that cowboy’s name. One approach is to explicitly check for the key with a conditional. Fix the below:

>>> cowboy = {'age': 32, 
                         'horse': 'mustang', 
                         'hat_size': 'large'}
>>> if 'name' in cowboy:
...        name = cowboy['some_name']
...    else:
...        name = 'The Man with No Name'
...
>>> name
'The Man with No Name'
A

This approach first checks if the name key exists in the dictionary, and if so, it returns the corresponding value. Otherwise, it returns a default value.

While explicitly checking for keys does work, it can easily be replaced with one line if you use .get():

name = cowboy.get(‘name’, ‘The Man with No Name’)

get() performs the same operations that were performed in the first approach, but now they’re handled automatically. If the key exists, then the proper value will be returned. Otherwise, the default value will get returned.

But what if you want to update the dictionary with a default value while still accessing the name key? .get() doesn’t really help you here, so Python offers a more elegant method with .setdefault():

name = cowboy.setdefault(‘name’, ‘The Man with No Name’)

.setdefault() accomplishes exactly the same thing as the snippet above. It checks if name exists in cowboy, and if so it returns that value. Otherwise, it sets cowboy[‘name’] to The Man with No Name and returns the new value.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

Handle Missing Dictionary Keys With collections.defaultdict()

Pretend you have a group of students, and you need to keep track of their grades on homework assignments. The input value is a list of tuples with the format (student_name, grade), but you want to easily look up all the grades for a single student without iterating over the list.

One way to store the grade data uses a dictionary that maps student names to lists of grades:

>>> student_grades = {}
>>> grades = [
...     ('elliot', 91),
...     ('neelam', 98),
...     ('bianca', 81),
...     ('elliot', 88),
... ]
>>> for name, grade in grades:
...        if name not in student_grades:
...            student_grades[name] = []
...        student_grades[name].append(grade)
...
>>> student_grades
{'elliot': [91, 88], 'neelam': [98], 'bianca': [81]}

In this approach, you iterate over the students and check if their names are already properties in the dictionary. If not, you add them to the dictionary with an empty list as the default value. You then append their actual grades to that student’s list of grades.

But there’s an even cleaner approach that uses a defaultdict, which extends standard dict functionality to allow you to set a default value that will be operated upon if the key doesn’t exist. How would we do this?

A

> > > from collections import defaultdict
student_grades = defaultdict(list)
for name, grade in grades:
… student_grades[name].append(grade)

In this case, you’re creating a defaultdict that uses the list() constructor with no arguments as a default factory method. list() with no arguments returns an empty list, so defaultdict calls list() if the name doesn’t exist and then allows the grade to be appended. If you want to get fancy, you could also use a lambda function as your factory value to return an arbitrary constant.

Leveraging a defaultdict can lead to cleaner application code because you don’t have to worry about default values at the key level. Instead, you can handle them once at the defaultdict level and afterwards act as if the key is always present.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

Count Hashable Objects With collections.Counter

You have a long string of words with no punctuation or capital letters and you want to count how many times each word appears.

You could use a dictionary or defaultdict and increment the counts, but collections.Counter provides a cleaner and more convenient way to do exactly that. Counter is a subclass of dict that uses 0 as the default value for any missing element and makes it easier to count occurrences of objects. How would you do this?

A

> > > from collections import Counter
words = “if there was there was but if \
… there was not there was not”.split()
counts = Counter(words)
counts
Counter({‘if’: 2, ‘there’: 4, ‘was’: 4, ‘not’: 2, ‘but’: 1})

When you pass in the list of words to Counter, it stores each word along with a count of how many times that word occurred in the list.

Are you curious what the two most common words were? Just use .most_common():

> > > counts.most_common(2)
[(‘there’, 4), (‘was’, 4)]

.most_common() is a convenience method and simply returns the n most frequent inputs by count.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Generate Permutations and Combinations With itertools

Interviewers love to give real life scenarios to make coding interviews seem less intimidating, so here’s a contrived example: you go to an amusement park and decide to figure out every possible pair of friends that could sit together on a roller coaster.

Unless generating these pairs is the primary purpose of the interview question, it’s likely that generating all the possible pairs is just a tedious step on the way towards a working algorithm. You could calculate them yourself with nested for-loops, or you could use the powerful itertools library.

itertools has multiple tools for generating iterable sequences of input data, but right now we’ll just focus on two common functions: itertools.permutations() and itertools.combinations().

Show how you would use this for the following code:

friends = [‘Monique’, ‘Ashish’, ‘Devon’, ‘Bernie’]

A

itertools.permutations() builds a list of all permutations, meaning it’s a list of every possible grouping of input values with a length matching the count parameter. The r keyword argument lets us specify how many values go in each grouping:

> > > import itertools
friends = [‘Monique’, ‘Ashish’, ‘Devon’, ‘Bernie’]
list(itertools.permutations(friends, r=2))
[(‘Monique’, ‘Ashish’), (‘Monique’, ‘Devon’), (‘Monique’, ‘Bernie’),
(‘Ashish’, ‘Monique’), (‘Ashish’, ‘Devon’), (‘Ashish’, ‘Bernie’),
(‘Devon’, ‘Monique’), (‘Devon’, ‘Ashish’), (‘Devon’, ‘Bernie’),
(‘Bernie’, ‘Monique’), (‘Bernie’, ‘Ashish’), (‘Bernie’, ‘Devon’)]

With permutations, the order of the elements matters, so (‘sam’, ‘devon’) represents a different pairing than (‘devon’, ‘sam’), meaning that they would both be included in the list.

itertools.combinations() builds combinations. These are also the possible groupings of the input values, but now the order of the values doesn’t matter. Because (‘sam’, ‘devon’) and (‘devon’, ‘sam’) represent the same pair, only one of them would be included in the output list:

> > > list(itertools.combinations(friends, r=2))
[(‘Monique’, ‘Ashish’), (‘Monique’, ‘Devon’), (‘Monique’, ‘Bernie’),
(‘Ashish’, ‘Devon’), (‘Ashish’, ‘Bernie’), (‘Devon’, ‘Bernie’)]

Since the order of the values matters with combinations, there are fewer combinations than permutations for the same input list. Again, because we set r to 2, each grouping has two names in it.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly