Concepts / Sorting Dictionaries by Value

Sorting Dictionaries by Value

urllib.request.urlopen() opens a web URL and returns a file-like object that you can iterate over line by line.

  • Programming

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

openeach linesplitupdateWeb URLFile-like responselines as bytesDecode linereadable stringSplit into wordsone word at a timeWord-count dictionaryword to total count
How does text move from a remote URL through line and word processing into dictionary entries?

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

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.

process Butprocess softprocess whatprocess lightprocess throughprocess yonderEmpty dictionary{}But{'But': 1}soft{'But': 1, 'soft': 1}what{'But': 1, 'soft': 1,'what': 1}light{'But': 1, 'soft': 1,'what': 1, 'light': 1}through{'But': 1, 'soft': 1,'what': 1, 'light': 1,'through': 1}yonder{'But': 1, 'soft': 1,'what': 1, 'light': 1,'through': 1, 'yonder': 1}
How does the word-count dictionary change as each word is processed?

A Repeated Word

Process the words red, blue, red using the update counts[word] = counts.get(word, 0) + 1.

red: red is not present, so counts.get('red', 0) returns 0 and the stored count becomes 1.

blue: blue is not present, so its stored count becomes 1.

red 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.

move positionmove positionwordkeycountfirst tuple elementcountvaluewordsecond tuple element
How does changing each entry from (key, value) to (value, key) make the dictionary value the first sorting criterion?

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.

python
Output
[(1, 'blue'), (2, 'green'), (2, 'red')]

Reading Tuple Sort Order

compare valuecompare value, then keycompare value, then key(1, blue)value 1(1, blue)smallest value(2, red)value 2(2, green)tie resolved by key(2, green)value 2(2, red)tie resolved by key
Given (value, key) tuples, what order does sorting produce, and what happens when values tie?

What do you think happens?

What will sorted() produce from [(3, 'oak'), (1, 'ash'), (3, 'elm')]?

  • [(1, 'ash'), (3, 'elm'), (3, 'oak')]
  • [(3, 'oak'), (3, 'elm'), (1, 'ash')]
  • [(1, 'ash'), (3, 'oak'), (3, 'elm')]
Reveal answer

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

  • Processing the byte line as though it were already a string

    Each 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.

    Fix: Decode the line first, then split the resulting string.

  • Resetting the count instead of incrementing it

    A repeated word is assigned 1 again, so its total occurrence count never accumulates.

    Fix: Use counts[word] = counts.get(word, 0) + 1.

  • Updating a different dictionary key than the current word

    Occurrences are collected under the wrong entry, so the dictionary no longer maps each word to its own total.

    Fix: Use the current word as the key in the update expression.

  • Sorting the original key-value pairs when the goal is value order

    The word is first, so it controls the primary tuple comparison.

    Fix: Build a new list shaped as (count, word) before calling sorted().

  • Expecting a dictionary to be rearranged in place by sorted()

    The technique constructs a list of tuples for sorting; the original dictionary remains the word-to-count mapping.

    Fix: Store and use the sorted list of (value, key) tuples.

Practice the Transformation

EASY

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}.

Reconstruct: The dictionary entries become (3, 'sun'), (1, 'rain'), and (3, 'wind').

Compare first elements: The tuple beginning with 1 comes before the tuples beginning with 3.

Resolve 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.
  2. Web lines arrive as bytes, so decode them before splitting into words.
  3. Use counts[word] = counts.get(word, 0) + 1 to initialize and increment word frequencies.
  4. A dictionary entry normally has the shape (key, value); rebuild it as (value, key) when the value should control sorting.
  5. Tuple sorting compares the first element first and uses later elements to resolve ties.

Key Takeaways

  • 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.