Python
Dictionary
List
Counting
Programming

Using a dictionary to count the items in a list

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Counting how often each value appears in a list is a core operation in analytics, data cleaning, and event processing. In Python, dictionaries provide an efficient one-pass solution with clear semantics. The best pattern depends on whether you need quick totals, normalized grouping, streaming updates, or top-frequency reporting.

Basic Dictionary Counting Pattern

The manual dictionary approach is simple and flexible.

python
1items = ["apple", "banana", "apple", "orange", "banana", "apple"]
2counts = {}
3
4for item in items:
5    counts[item] = counts.get(item, 0) + 1
6
7print(counts)

This runs in linear time for typical hashable values and is easy to extend with custom logic before incrementing.

Use Counter for Concise Code

When you only need standard frequency counting, collections.Counter is shorter and expressive.

python
1from collections import Counter
2
3items = ["apple", "banana", "apple", "orange", "banana", "apple"]
4freq = Counter(items)
5
6print(freq)
7print(freq["apple"])
8print(freq.most_common(2))

Counter is a dictionary subclass, so it remains compatible with many dictionary workflows.

Normalize Input Before Counting

Real data often includes case and whitespace variation. If business logic treats those values as equivalent, normalize first.

python
1def normalize_token(token: str) -> str:
2    return token.strip().casefold()
3
4raw = [" Apple", "apple", "APPLE ", "Banana"]
5counts = {}
6
7for token in raw:
8    key = normalize_token(token)
9    counts[key] = counts.get(key, 0) + 1
10
11print(counts)

Skipping normalization leads to fragmented counts and misleading reports.

Counting Complex Objects with Derived Keys

List elements are not always plain strings. For dictionaries or objects, define a stable key based on your uniqueness rule.

python
1records = [
2    {"country": "CA", "city": "Toronto"},
3    {"country": "US", "city": "Austin"},
4    {"country": "CA", "city": "Toronto"},
5]
6
7counts = {}
8for row in records:
9    key = (row["country"], row["city"])
10    counts[key] = counts.get(key, 0) + 1
11
12print(counts)

Choosing the right key is critical. In some domains only one field should define identity.

Streaming Updates for Event Pipelines

When data arrives continuously, update counts incrementally instead of loading full datasets in memory.

python
1def update_count(counts: dict, value):
2    counts[value] = counts.get(value, 0) + 1
3
4counts = {}
5for event in ["view", "click", "view", "purchase", "view"]:
6    update_count(counts, event)
7
8print(counts)

This pattern fits background workers and log consumers where data volume is unbounded.

Ranking Results by Frequency

Dictionary insertion order is not frequency order. Sort explicitly when output needs ranking.

python
counts = {"apple": 3, "banana": 2, "orange": 1}
ranked = sorted(counts.items(), key=lambda pair: pair[1], reverse=True)
print(ranked)

For very large maps and top-N use cases, heapq.nlargest can be more efficient than sorting everything.

Memory and Performance Considerations

Counting is usually O(n) time and O(k) memory where k is unique key count. High-cardinality keys can consume significant memory.

If cardinality is huge, consider:

  • Partitioned counting by key range.
  • Periodic flushing to external storage.
  • Approximate counting techniques when exact counts are not mandatory.

For most application workloads, regular dictionaries or Counter remain the practical default.

Testing Frequency Logic

Unit tests should include:

  • Empty list input.
  • Mixed case and whitespace examples.
  • Expected frequency ordering after sorting.
  • Non-string keys if your pipeline allows them.

Small tests catch many regressions after key-normalization changes.

Common Pitfalls

  • Forgetting default initialization and triggering key errors.
  • Counting raw values when business rules require normalization.
  • Using nested loops and creating avoidable quadratic performance.
  • Assuming dictionary iteration order reflects highest frequency.
  • Defining uniqueness keys inconsistently across code paths.

Summary

  • Dictionary counting is an efficient one-pass way to compute frequencies.
  • 'dict.get is flexible, while Counter is concise for standard cases.'
  • Normalize inputs when semantic equality differs from literal equality.
  • Use derived keys for complex records.
  • Sort explicitly when consumers need ranked frequency output.

Course illustration
Course illustration

All Rights Reserved.