Archive
Three ways of creating dictionaries in Python
Dictionaries are the fundamental data structure in Python, and a key tool in any Python programmer’s arsenal. They allow O(1) lookup speed, and have been heavily optimized for memory overhead and lookup speed efficiency.
Today I”m going to show you three ways of constructing a Python dictionary, as well as some additional tips and tricks.
Dictionary literals
Perhaps the most commonly used way of constructing a python dictionary is with curly bracket syntax:
d = {"age":25}
As dictionaries are mutable, you need not know all the entries in advance:
# Empty dict d = {} # Fill in the entries one by one d["age"] = 25
From a list of tuples
You can also construct a dictionary from a list (or any iterable) of key, value pairs. For instance:
d = dict([("age", 25)])
This is perhaps most useful in the context of a list comprehension:
class Person(object): def __init__(self, name, profession): self.name = name self.profession = profession people = [Person("Nick", "Programmer"), Person("Alice","Engineer")] professions = dict([ (p.name, p.profession) for p in people ]) >>> print professions {"Nick": "Programmer", "Alice": "Engineer"}
This is equivalent, though a bit shorter, to the following:
people = [Person("Nick", "Programmer"), Person("Alice","Engineer")] professions = {} for p in people: professions[p.name] = p.profession
This form of creating a dictionary is good for when you have a dynamic rather than static list of elements.
From two parallel lists
This method of constructing a dictionary is intimately related to the prior example. Say you have two lists of elements, perhaps pulled from a database table:
# Static lists for purpose of illustration names = ["Nick", "Alice", "Kitty"] professions = ["Programmer", "Engineer", "Art Therapist"]
If you wished to create a dictionary from name to profession, you could do the following:
professions_dict = {} for i in range(len(names)): professions_dict[names[i]] = professions[i]
This is not ideal, however, as it involves an explicit iterator, and is starting to look like Java. The more Pythonic way to handle this case would be to use the zip
method, which combines two iterables:
print zip(range(5), ["a","b","c","d","e"]) [(0, "a"), (1, "b"), (2, "c"), (3, "d"), (4, "e")] names_and_professions = zip(names, professions) print names_and_professions [("Nick", "Programmer"), ("Alice", "Engineer"), ("Kitty", "Art Therapist")] for name, profession in names_and_professions: professions_dict[name] = profession
As you can see, this is extremely similar to the previous section. You can dispense the iteration, and instead use the dict
method:
professions_dict = dict(names_and_professions) # You can dispence the extra variable and create an anonymous # zipped list: professions_dict = dict(zip(names, professions))
Further reading
Car Talk Puzzler #4: Flipping Ages
RAY: This was sent in many weeks ago by Wendy Gladstone, and as usual I tweaked it a little bit.
She writes: “Recently I had a visit with my mom and we realized that the two digits that make up my age when reversed resulted in her age. For example, if she’s 73, I’m 37. We wondered how often this has happened over the years but we got sidetracked with other topics and we never came up with an answer.
“When I got home I figured out that the digits of our ages have been reversible six times so far. I also figured out that if we’re lucky it would happen again in a few years, and if we’re really lucky it would happen one more time after that. In other words, it would have happened 8 times over all. So the question is, how old am I now?”
Here’s the fourth in my Car Talk Puzzler series; today I’m going to be using Python because it’s my current favorite language, and because it’s well suited to filtering, mapping, etc. I won’t put too much commentary here.
# Find all the ages such that the second age is the reverse of the first age. Don't worry that there are a lot of impossibilities; we'll fix it through filtering # Note that [::-1] is the slice operator that says iterate backwards through the string; this effectively reverses the list. matching_ages = map(lambda x:(x, int(str(x)[::-1])), range(0,100)) matching_ages # OUT: [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6), (7, 7), (8, 8), (9, 9), (10, 1), (11, 11), (12, 21), (13, 31), (14, 41), (15, 51), (16, 61), (17, 71), (18, 81), (19, 91), (20, 2), (21, 12), (22, 22), (23, 32), (24, 42), (25, 52), (26, 62), (27, 72), (28, 82), (29, 92), (30, 3), (31, 13), (32, 23), (33, 33), (34, 43), (35, 53), (36, 63), (37, 73), (38, 83), (39, 93), (40, 4), (41, 14), (42, 24), (43, 34), (44, 44), (45, 54), (46, 64), (47, 74), (48, 84), (49, 94), (50, 5), (51, 15), (52, 25), (53, 35), (54, 45), (55, 55), (56, 65), (57, 75), (58, 85), (59, 95), (60, 6), (61, 16), (62, 26), (63, 36), (64, 46), (65, 56), (66, 66), (67, 76), (68, 86), (69, 96), (70, 7), (71, 17), (72, 27), (73, 37), (74, 47), (75, 57), (76, 67), (77, 77), (78, 87), (79, 97), (80, 8), (81, 18), (82, 28), (83, 38), (84, 48), (85, 58), (86, 68), (87, 78), (88, 88), (89, 98), (90, 9), (91, 19), (92, 29), (93, 39), (94, 49), (95, 59), (96, 69), (97, 79), (98, 89), (99, 99)] # Here we filter by only allowing matches in which the mother's age is greater than that of the child. Note the use of a lambda expression, basically an anonymous function. filtered1 = filter(lambda (mother,child):mother > child, matching_ages) filtered1 # OUT: [(10, 1), (20, 2), (21, 12), (30, 3), (31, 13), (32, 23), (40, 4), (41, 14), (42, 24), (43, 34), (50, 5), (51, 15), (52, 25), (53, 35), (54, 45), (60, 6), (61, 16), (62, 26), (63, 36), (64, 46), (65, 56), (70, 7), (71, 17), (72, 27), (73, 37), (74, 47), (75, 57), (76, 67), (80, 8), (81, 18), (82, 28), (83, 38), (84, 48), (85, 58), (86, 68), (87, 78), (90, 9), (91, 19), (92, 29), (93, 39), (94, 49), (95, 59), (96, 69), (97, 79), (98, 89)] # Assume that the mother was at least 15 when she had the kid, and no more than 60 filtered2 = filter(lambda(mother, child):mother-child >= 15 and mother-child < 60, filtered1) filtered2 # OUT: [(20, 2), (30, 3), (31, 13), (40, 4), (41, 14), (42, 24), (50, 5), (51, 15), (52, 25), (53, 35), (60, 6), (61, 16), (62, 26), (63, 36), (64, 46), (71, 17), (72, 27), (73, 37), (74, 47), (75, 57), (82, 28), (83, 38), (84, 48), (85, 58), (86, 68), (93, 39), (94, 49), (95, 59), (96, 69), (97, 79)] len(filtered2) # OUT: 30 # Create a new list comprised of the differences in age between mother and child age_diff = map(lambda(mother,child):mother-child, filtered2) age_diff # OUT: [18, 27, 18, 36, 27, 18, 45, 36, 27, 18, 54, 45, 36, 27, 18, 54, 45, 36, 27, 18, 54, 45, 36, 27, 18] sorted(age_diff) # OUT: [18, 18, 18, 18, 18, 18, 18, 27, 27, 27, 27, 27, 27, 36, 36, 36, 36, 36, 45, 45, 45, 45, 54, 54, 54] # The puzzler states that it's will happen a total of 8 times; that matches the age difference of 18 years filter(lambda(mother,child):mother-child == 18, filtered3) # OUT: [(20, 2), (31, 13), (42, 24), (53, 35), (64, 46), (75, 57), (86, 68), (97, 79)]
Thus the mother is currently 75 years old and the daughter is 57. Tada