Skip to Content
Course content

229: Collections Module: Counter

Click on the "Edit" button in the top corner of the screen to edit your slide content.

You've probably used a dictionary to count things before. The pattern is always the same: check if the key exists, if not, initialize it to zero, then increment. It works, but it's tedious boilerplate. That's why I almost always reach for collections.Counter when I need to tally items.

Let's build something practical. Imagine we're writing a small tool for a game to analyze "loot drops" from a monster. We want to know exactly how many of each item dropped over a series of runs to see if the drop rates feel balanced.

Tallying the loot drops

First, I'll start with a raw list of items. In a real scenario, this might come from a CSV or a database, but for now, a simple list will do.

from collections import Counter

loot_drops = [
    "Rusty Sword", "Health Potion", "Gold Coin", "Gold Coin", 
    "Health Potion", "Gold Coin", "Iron Shield", "Gold Coin", 
    "Health Potion", "Mana Potion", "Gold Coin"
]

# Instead of a for-loop and a dict, I just pass the list straight in
inventory = Counter(loot_drops)

print(inventory)
# Output: Counter({'Gold Coin': 5, 'Health Potion': 3, 'Mana Potion': 1, 'Iron Shield': 1, 'Rusty Sword': 1})

The Counter object is actually a subclass of a dictionary, so it behaves like one, but it's specialized for counting. The magic here is that I didn't have to write a single if key not in dict statement.

Finding the most common items

Usually, we don't just want the whole list; we want the "top X" items. This is where most_common() comes in. I'll use it to find the two most frequent drops.

top_two = inventory.most_common(2)
print(top_two)
# Output: [('Gold Coin', 5), ('Health Potion', 3)]

Now, here is where I often trip up when I'm coding quickly. I remember a time when I tried to access the count of the top item by treating the result of most_common() like a dictionary. I wrote something like top_two['Gold Coin'] and got a TypeError.

The mistake is forgetting that most_common() returns a list of tuples, not a dictionary. If you want to work with those results, you have to iterate through them or use index offsets:

# The wrong way: top_two['Gold Coin'] -> TypeError

# The right way:
for item, count in top_two:
    print(f"The {item} dropped {count} times.")

Updating and subtracting counts

One of the most powerful things about Counter that people overlook is that you can perform mathematical operations on them. Let's say the player uses some items. Instead of manually decrementing values, I can create a second Counter for "consumed" items and subtract it from the first.

# Items the player used
consumed = Counter(["Gold Coin", "Gold Coin", "Health Potion"])

# Subtracting one counter from another
remaining_loot = inventory - consumed

print(remaining_loot)
# Output: Counter({'Gold Coin': 3, 'Health Potion': 2, 'Mana Potion': 1, 'Iron Shield': 1, 'Rusty Sword': 1})

I love this because it keeps the logic clean. I don't have to worry about whether a count drops below zero; Counter subtraction automatically removes keys with a result of zero or less, keeping the data tidy.




📋 Practical Task

Analyze Server Log Status Codes

You have been given a list of HTTP status codes captured from a server log. Your task is to use the Counter class to analyze the traffic.

logs = ["200", "404", "500", "200", "200", "404", "200", "500", "500", "500", "200", "403", "200"]

Write a script that does the following:

  1. Creates a Counter object to tally the status codes.
  2. Prints the total number of "200" (Success) responses.
  3. Prints the single most common status code and its count.
  4. Creates a second Counter representing "resolved" issues: {"500": 2, "404": 1}.
  5. Subtracts the resolved issues from the original tally and prints the remaining issues that still need attention.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.