Sorting Dictionaries by Value
Tuple sorting compares the first element first, so the word controls the primary ordering.
Try it: Sorting with key= and reverse=
How sorted() and list.sort() compute key(item) once per item, order the items by those keys with Python's comparison rules, and keep equal keys in their original order — including py4e's sort-a-dict-by-value pattern.
How it works
- Decorate: call the key function once on every item (no key means the item itself is compared).
- Compare keys with Python's rules: ints by value, strs by code point ('Z' < 'a'), tuples item by item.
- Order the items by key; reverse=True puts the largest key first.
- Stable: items with equal keys keep their original relative order, also with reverse=True.
- sorted() returns a new list; list.sort() rearranges the list in place and returns None; [:N] keeps the first N.
Default run (12 steps): 5 items in their original order. Python will call lambda t: t[1] once per item. … sorted() returned a new list: result = [('fig', 5), ('kiwi', 5), ('pear', 3), ('apple', 3), ('date', 1)].
Simplified: Up to 10 items of one kind (ints, short ASCII words, (word, count) tuples or a small dict) and a fixed menu of key functions. The sorting algorithm itself (Timsort) is not shown — only what it guarantees: the order by key and stability.
Loading the simulation…
Try it: Counting Words with a Dictionary
The py4e histogram pattern: split each line into words, count them with counts[word] = counts.get(word, 0) + 1, then find the most common word with a max loop or by sorting (count, word) tuples in reverse.
How it works
- Optionally remove punctuation with str.translate and lower-case the line, then split() it into words.
- For each word: counts.get(word, 0) returns the current count or 0 for a new word; store it plus one (or the if word not in counts form).
- A dict remembers insertion order: a word's position is fixed the first time it is seen.
- Max loop: keep the word whose count is strictly larger than the best so far (the first word wins a tie).
- Or build [(count, word) …], sort with reverse=True (ties ordered by the word, reversed) and slice [:N].
Default run (25 steps): Start with an empty dict. The text has 3 lines. … [:3] keeps the top 3: [(5, 'the'), (2, 'sat'), (2, 'on')].
Simplified: Printable-ASCII text up to 320 characters, 8 lines and 60 words, typed in the lab instead of read from a file or URL.
Loading the simulation…
From Web Text to Ranked Words
Suppose you download a text file and want to discover which words occur most often. Counting manually is tedious and error-prone. A Python program can retrieve the text, process every word, store frequencies in a dictionary, and then prepare those dictionary entries for sorting by frequency.
The complete task has two connected parts. First, urllib.request.urlopen() opens a web URL and returns a file-like object. You can iterate over that object line by line as you would iterate over a local file. Second, you transform the text into a dictionary whose keys are words and whose values are total occurrence counts. To sort by those counts, you rebuild each dictionary entry in the opposite order: (value, key) instead of (key, value).
The Counting Pipeline
The response from urlopen() is file-like, but each line arrives as bytes. Decode each line to a string before splitting it into words. The outer loop handles lines; the inner loop handles the words within each line. Every word then updates the same counts dictionary, so its value represents the total across the entire text rather than only the current line.
import urllib.request
counts = {}
with urllib.request.urlopen(url) as response:
for line in response:
text = line.decode()
for word in text.split():
counts[word] = counts.get(word, 0) + 1- 1The response can be iterated over line by line.
- 2
decode()converts each line from bytes into a string. - 3
split()supplies the individual words for the inner loop. - 4
counts.get(word, 0)returns the current count when the word exists and 0 when it does not. - 5Adding 1 initializes a new word at 1 or increments an existing word.
- Open the remote URL and receive a file-like response.
- Start with an empty dictionary.
- Read one byte line at a time.
- Decode the bytes into readable text.
- Visit each word in the decoded line.
- Use the existing count or 0, then add 1.
Tracing Each Dictionary Update
A useful way to understand the counter is to pause after every word. The source uses the first two lines But soft what and light through yonder as a small tracing example. Each new word receives a count of 1 because it has not appeared before. If a word appears again later, the dictionary retrieves its current count and increases it.
A Repeated Word
Process the words red, blue, red using the update counts[word] = counts.get(word, 0) + 1.
- 1red
red is not present, so
counts.get('red', 0)returns 0 and the stored count becomes 1. - 2blue
blue is not present, so its stored count becomes 1.
- 3red again
red is already present with count 1, so the expression stores 2.
The final dictionary is {'red': 2, 'blue': 1}.
Making Values Sortable
A word-count dictionary naturally stores entries as (key, value): the word is the key and its frequency is the value. If you place those entries directly into a list, the word appears first in each tuple. Tuple sorting compares the first element first, so the word controls the primary ordering.
The solution is to reconstruct every entry as (value, key). For word counts, that means (count, word). Now the count occupies the first tuple position, so a simple sorted() call compares counts first. The word moves to the second position and can be used when two counts are equal.
[(1, 'blue'), (2, 'green'), (2, 'red')]Reading Tuple Sort Order
What do you think happens?
What will sorted() produce from [(3, 'oak'), (1, 'ash'), (3, 'elm')]?
Reveal answer
[(1, 'ash'), (3, 'elm'), (3, 'oak')]
The first tuple element is compared first, so 1 comes before 3. The two tuples beginning with 3 tie on the first element, so their second elements are compared: elm comes before oak.
Tuple comparison is lexicographic: Python examines the first element first. If the first elements differ, that decides the order. If they are equal, comparison continues to the next element. Therefore, with (count, word) tuples, counts determine the main order and words determine the order within equal-count groups.
Mistakes in Counting and Sorting
Common mistake Processing the byte line as though it were already a string
What it looks likeSplitting line immediately without decoding it
Why it failsEach line from the web source arrives as bytes, so it must be decoded before it can be treated as readable text and split into words.
Do this insteadDecode the line first, then split the resulting string.
Common mistake Resetting the count instead of incrementing it
What it looks likecounts[word] = 1 for every encounter
Why it failsA repeated word is assigned 1 again, so its total occurrence count never accumulates.
Do this insteadUse counts[word] = counts.get(word, 0) + 1.Common mistake Updating a different dictionary key than the current word
What it looks likeUsing a fixed key while looping through words
Why it failsOccurrences are collected under the wrong entry, so the dictionary no longer maps each word to its own total.
Do this insteadUse the current word as the key in the update expression.
Common mistake Sorting the original key-value pairs when the goal is value order
What it looks likeSorting entries shaped as (word, count)
Why it failsThe word is first, so it controls the primary tuple comparison.
Do this insteadBuild a new list shaped as (count, word) before calling sorted().
Common mistake Expecting a dictionary to be rearranged in place by sorted()
What it looks likeTreating sorted_pairs as though counts itself had been sorted
Why it failsThe technique constructs a list of tuples for sorting; the original dictionary remains the word-to-count mapping.
Do this insteadStore and use the sorted list of (value, key) tuples.
Practice the Transformation
A dictionary contains {'sun': 3, 'rain': 1, 'wind': 3}. Construct the list of (value, key) tuples and predict the result of sorted() before checking your work.
Hints
- Loop through the dictionary's key and value together.
- Append the value first and the key second.
- Compare the counts first; compare the words only when counts tie.
Checking the Practice Result
Sort the reconstructed entries for {'sun': 3, 'rain': 1, 'wind': 3}.
- 1Reconstruct
The dictionary entries become (3, 'sun'), (1, 'rain'), and (3, 'wind').
- 2Compare first elements
The tuple beginning with 1 comes before the tuples beginning with 3.
- 3Resolve the tie
The two tuples beginning with 3 are compared by their second elements, rain-related entries being compared alphabetically as words; between sun and wind, sun comes first.
[(1, 'rain'), (3, 'sun'), (3, 'wind')]
Key Takeaways
- 1
urlopen()returns a file-like object that can be iterated over line by line. - 2Web lines arrive as bytes, so decode them before splitting into words.
- 3Use counts[word] =
counts.get(word, 0)+ 1 to initialize and increment word frequencies. - 4A dictionary entry normally has the shape (key, value); rebuild it as (value, key) when the value should control sorting.
- 5Tuple sorting compares the first element first and uses later elements to resolve ties.
At a glance
- Retrieve remote text as a file-like response, decode each byte line, and process its words.
- Maintain cumulative word frequencies with
counts.get(word, 0)+ 1. - Trace the dictionary after each update to locate counting errors.
- Reconstruct entries as (value, key) so the desired value becomes the first tuple comparison.
- When values tie, the tuple's later element determines the order.