Skip to content

Commit b5a27c1

Browse files
authored
Merge pull request #279 from realpython/sort-dict
How to Sort a Python Dictionary
2 parents 9420ac2 + 1762d14 commit b5a27c1

File tree

8 files changed

+289
-0
lines changed

8 files changed

+289
-0
lines changed

sort-python-dictionary/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# How to Sort a Python Dictionary
2+
3+
Corresponding code for ["How to Sort a Python Dictionary"](https://realpython.com/sort-python-dictionary/)
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
from timeit import timeit
2+
3+
dict_to_order = {
4+
1: "requests",
5+
2: "pip",
6+
3: "jinja",
7+
4: "setuptools",
8+
5: "pandas",
9+
6: "numpy",
10+
7: "black",
11+
8: "pillow",
12+
9: "pyparsing",
13+
10: "boto3",
14+
11: "botocore",
15+
12: "urllib3",
16+
13: "s3transfer",
17+
14: "six",
18+
15: "python-dateutil",
19+
16: "pyyaml",
20+
17: "idna",
21+
18: "certifi",
22+
19: "typing-extensions",
23+
20: "charset-normalizer",
24+
21: "awscli",
25+
22: "wheel",
26+
23: "rsa",
27+
}
28+
29+
sorted_with_lambda = "sorted(dict_to_order.items(), key=lambda item: item[1])"
30+
sorted_with_itemgetter = "sorted(dict_to_order.items(), key=itemgetter(1))"
31+
32+
sorted_with_lambda_time = timeit(stmt=sorted_with_lambda, globals=globals())
33+
sorted_with_itemgetter_time = timeit(
34+
stmt=sorted_with_itemgetter,
35+
setup="from operator import itemgetter",
36+
globals=globals(),
37+
)
38+
39+
print(
40+
f"""\
41+
{sorted_with_lambda_time=:.2f} seconds
42+
{sorted_with_itemgetter_time=:.2f} seconds
43+
itemgetter is {(
44+
sorted_with_lambda_time / sorted_with_itemgetter_time
45+
):.2f} times faster"""
46+
)
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
from timeit import timeit
2+
3+
lookups = [15, 18, 19, 16, 6, 12, 5, 3, 9, 20, 2, 10, 13, 17, 4, 14, 11, 7, 8]
4+
5+
list_setup = """
6+
from samples import list_of_dictionaries
7+
8+
def get_key_from_list(key):
9+
for item in list_of_dictionaries:
10+
if item["id"] == key:
11+
return item
12+
"""
13+
14+
dict_setup = "from samples import dictionary_of_dictionaries"
15+
16+
lookup_list = """
17+
for key in lookups:
18+
get_key_from_list(key)
19+
"""
20+
21+
lookup_dict = """
22+
for key in lookups:
23+
dictionary_of_dictionaries[key]
24+
"""
25+
26+
lookup_list_time = timeit(
27+
stmt=lookup_list, setup=list_setup, globals=globals()
28+
)
29+
lookup_dict_time = timeit(
30+
stmt=lookup_dict, setup=dict_setup, globals=globals()
31+
)
32+
33+
print(
34+
f"""\
35+
{lookup_list_time=:.2f} seconds
36+
{lookup_dict_time=:.2f} seconds
37+
dict is {(lookup_list_time / lookup_dict_time):.2f} times faster"""
38+
)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
from timeit import timeit
2+
3+
sorting_list = "sorted(list_of_dictionaries, key=lambda item:item['age'])"
4+
sorting_dict = """
5+
dict(
6+
sorted(
7+
dictionary_of_dictionaries.items(), key=lambda item: item[1]['age']
8+
)
9+
)
10+
"""
11+
12+
sorting_list_time = timeit(
13+
stmt=sorting_list,
14+
setup="from samples import list_of_dictionaries",
15+
globals=globals(),
16+
)
17+
sorting_dict_time = timeit(
18+
stmt=sorting_dict,
19+
setup="from samples import dictionary_of_dictionaries",
20+
globals=globals(),
21+
)
22+
23+
print(
24+
f"""\
25+
{sorting_list_time=:.2f} seconds
26+
{sorting_dict_time=:.2f} seconds
27+
list is {(sorting_dict_time/sorting_list_time):.2f} times faster"""
28+
)
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
data = {
2+
193: {"name": "John", "age": 30, "skills": {"python": 8, "js": 7}},
3+
209: {"name": "Bill", "age": 15, "skills": {"python": 6}},
4+
746: {"name": "Jane", "age": 58, "skills": {"js": 2, "python": 5}},
5+
109: {"name": "Jill", "age": 83, "skills": {"java": 10}},
6+
984: {"name": "Jack", "age": 28, "skills": {"c": 8, "assembly": 7}},
7+
765: {"name": "Penelope", "age": 76, "skills": {"python": 8, "go": 5}},
8+
598: {"name": "Sylvia", "age": 62, "skills": {"bash": 8, "java": 7}},
9+
483: {"name": "Anna", "age": 24, "skills": {"js": 10}},
10+
277: {"name": "Beatriz", "age": 26, "skills": {"python": 2, "js": 4}},
11+
}
12+
13+
14+
def get_python(item):
15+
skills = item[1]["skills"]
16+
if "python" in skills:
17+
return skills["python"]
18+
else:
19+
# Return value that is equivalent to having no Python skill
20+
return 0
21+
22+
23+
print(sorted(data.items(), key=get_python, reverse=True))
24+
25+
# Doing the same thing with lambda function and conditional expression
26+
print(
27+
sorted(
28+
data.items(),
29+
key=lambda item: item[1]["skills"]["python"]
30+
if "python" in item[1]["skills"]
31+
else 0,
32+
reverse=True,
33+
)
34+
)

sort-python-dictionary/samples.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
dictionary_of_dictionaries = {
2+
1: {"first_name": "Dorthea", "last_name": "Emmanuele", "age": 29},
3+
2: {"first_name": "Evelina", "last_name": "Ferras", "age": 91},
4+
3: {"first_name": "Frederica", "last_name": "Livesay", "age": 99},
5+
4: {"first_name": "Murray", "last_name": "Linning", "age": 36},
6+
5: {"first_name": "Annette", "last_name": "Garioch", "age": 93},
7+
6: {"first_name": "Rozamond", "last_name": "Todd", "age": 36},
8+
7: {"first_name": "Tiffi", "last_name": "Varian", "age": 28},
9+
8: {"first_name": "Noland", "last_name": "Cowterd", "age": 51},
10+
9: {"first_name": "Dyana", "last_name": "Fallows", "age": 100},
11+
10: {"first_name": "Diahann", "last_name": "Cutchey", "age": 44},
12+
11: {"first_name": "Georgianne", "last_name": "Steinor", "age": 32},
13+
12: {"first_name": "Sabina", "last_name": "Lourens", "age": 31},
14+
13: {"first_name": "Lynde", "last_name": "Colbeck", "age": 35},
15+
14: {"first_name": "Abdul", "last_name": "Crisall", "age": 84},
16+
15: {"first_name": "Quintus", "last_name": "Brando", "age": 95},
17+
16: {"first_name": "Rowena", "last_name": "Geraud", "age": 21},
18+
17: {"first_name": "Maurice", "last_name": "MacAindreis", "age": 83},
19+
18: {"first_name": "Pall", "last_name": "O'Cullinane", "age": 79},
20+
19: {"first_name": "Kermie", "last_name": "Willshere", "age": 20},
21+
20: {"first_name": "Holli", "last_name": "Tattoo", "age": 88},
22+
}
23+
24+
list_of_dictionaries = [
25+
{"id": 1, "first_name": "Dorthea", "last_name": "Emmanuele", "age": 29},
26+
{"id": 2, "first_name": "Evelina", "last_name": "Ferras", "age": 91},
27+
{"id": 3, "first_name": "Frederica", "last_name": "Livesay", "age": 99},
28+
{"id": 4, "first_name": "Murray", "last_name": "Linning", "age": 36},
29+
{"id": 5, "first_name": "Annette", "last_name": "Garioch", "age": 93},
30+
{"id": 6, "first_name": "Rozamond", "last_name": "Todd", "age": 36},
31+
{"id": 7, "first_name": "Tiffi", "last_name": "Varian", "age": 28},
32+
{"id": 8, "first_name": "Noland", "last_name": "Cowterd", "age": 51},
33+
{"id": 9, "first_name": "Dyana", "last_name": "Fallows", "age": 100},
34+
{"id": 10, "first_name": "Diahann", "last_name": "Cutchey", "age": 44},
35+
{"id": 11, "first_name": "Georgianne", "last_name": "Steinor", "age": 32},
36+
{"id": 12, "first_name": "Sabina", "last_name": "Lourens", "age": 31},
37+
{"id": 13, "first_name": "Lynde", "last_name": "Colbeck", "age": 35},
38+
{"id": 14, "first_name": "Abdul", "last_name": "Crisall", "age": 84},
39+
{"id": 15, "first_name": "Quintus", "last_name": "Brando", "age": 95},
40+
{"id": 16, "first_name": "Rowena", "last_name": "Geraud", "age": 21},
41+
{"id": 17, "first_name": "Maurice", "last_name": "MacAindreis", "age": 83},
42+
{"id": 18, "first_name": "Pall", "last_name": "O'Cullinane", "age": 79},
43+
{"id": 19, "first_name": "Kermie", "last_name": "Willshere", "age": 20},
44+
{"id": 20, "first_name": "Holli", "last_name": "Tattoo", "age": 88},
45+
]
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Reviewing the sorted() function by sorting a list
2+
numbers = [5, 3, 4, 3, 6, 7, 3, 2, 3, 4, 1]
3+
sorted(numbers)
4+
words = ["aa", "ab", "ac", "ba", "cb", "ca"]
5+
sorted(words)
6+
7+
8+
def select_second_character(word): # Sort key
9+
return word[1]
10+
11+
12+
sorted(words, key=select_second_character)
13+
14+
# Feeding dictionary directly into sorted() function
15+
people = {3: "Jim", 2: "Jack", 4: "Jane", 1: "Jill"}
16+
sorted(people) # Returns list of sorted keys (values gone)
17+
18+
# Getting dictionary views
19+
people = {3: "Jim", 2: "Jack", 4: "Jane", 1: "Jill"}
20+
people.items()
21+
22+
people = {3: "Jim", 2: "Jack", 4: "Jane", 1: "Jill"}
23+
view = people.items()
24+
people[2] = "Elvis"
25+
print(view) # View has been updated
26+
27+
# Feeding dictionary view directly into sorted() function
28+
people = {3: "Jim", 2: "Jack", 4: "Jane", 1: "Jill"}
29+
sorted(people.items()) # Sorts by key
30+
31+
# Using a sort key when sorting dictionary views
32+
people = {3: "Jim", 2: "Jack", 4: "Jane", 1: "Jill"}
33+
34+
35+
def value_getter(item): # Sort key
36+
return item[1]
37+
38+
39+
sorted(people.items(), key=value_getter)
40+
sorted(people.items(), key=lambda item: item[1]) # Sort key as lambda function
41+
42+
43+
# Building a dictionary from the list returned from the sorted() function
44+
sorted_people = sorted(people.items(), key=lambda item: item[1])
45+
46+
sorted_people_dict = {} # Using a for loop
47+
for key, value in sorted_people:
48+
sorted_people_dict[key] = value
49+
50+
sorted_people = sorted(people.items(), key=lambda item: item[1])
51+
sorted_people_dict = dict(sorted_people) # dictionary constructor
52+
53+
sorted_people_dict = { # dictionary comprehension that swaps keys and values
54+
value: key
55+
for key, value in sorted(people.items(), key=lambda item: item[1])
56+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
from operator import itemgetter
2+
3+
item = ("name", "Guido")
4+
5+
getter = itemgetter(0)
6+
getter(item) # Returns "name"
7+
8+
getter = itemgetter(1)
9+
getter(item) # Returns "Guido"
10+
11+
12+
fruit_inventory = [("banana", 5), ("orange", 15), ("apple", 3), ("kiwi", 0)]
13+
14+
# Sort by key
15+
sorted(fruit_inventory, key=itemgetter(0))
16+
17+
# Sort by value
18+
sorted(fruit_inventory, key=itemgetter(1))
19+
20+
# Raises IndexError
21+
# sorted(fruit_inventory, key=itemgetter(2))
22+
23+
24+
people = {3: "Jim", 2: "Jack", 4: "Jane", 1: "Jill"}
25+
26+
sorted(people.items(), key=itemgetter(1)) # Sort by value
27+
28+
29+
scores = {
30+
"Jack": 14,
31+
"Jill": 14,
32+
"John": 15,
33+
"Jane": 15,
34+
"Jim": 14,
35+
"Jess": 14,
36+
}
37+
38+
# Sorts by value, but keeps names in alphabetical order
39+
print(sorted(scores.items(), key=itemgetter(1, 0)))

0 commit comments

Comments
 (0)