Python - Is a dictionary slow to find frequency of each character?
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.
Introduction
No — Python dictionaries are not slow for character frequency counting. Dictionary lookups and insertions are O(1) average-case, making them one of the most efficient data structures for this task. A manual dictionary loop, collections.Counter, and defaultdict(int) all use hash tables internally and perform similarly. The fastest built-in option is collections.Counter, which is implemented in C (CPython). For absolute maximum speed on large strings, str.count() per character or NumPy approaches can be marginally faster.
Basic Dictionary Approach
Each in check and [] assignment is O(1) on average. Total time is O(n) where n is the string length.
collections.Counter — Recommended
Counter is a dict subclass with a C-optimized __init__ that counts elements faster than a Python loop.
defaultdict(int) Approach
defaultdict(int) auto-creates missing keys with value 0, eliminating the if key in dict check.
dict.get() Approach
get(key, default) returns 0 for missing keys. Slightly slower than defaultdict but needs no import.
Performance Benchmarks
Counter is ~2-3x faster than manual Python loops because its counting loop runs in C.
Why Dictionaries Are Fast
Python dictionaries use hash tables with:
- O(1) average lookup: Hash the key, jump to the bucket, compare
- O(1) average insertion: Same hash + bucket logic
- Dynamic resizing: The table grows (typically doubles) when 2/3 full
- Open addressing: Collisions are handled by probing, not chaining
For character frequency, the number of unique keys is at most 256 (ASCII) or ~150K (Unicode), so collisions are rare and the hash table stays small.
Alternative: str.count() Per Character
For a known small alphabet:
str.count() is C-implemented and fast per call, but iterates the entire string once per unique character. For strings with few unique characters, this can beat Counter. For strings with many unique characters, Counter wins.
NumPy for Very Large Strings
NumPy's bincount is the fastest option for ASCII strings over ~1MB because it operates on contiguous memory without Python object overhead.
Common Pitfalls
- Assuming dictionaries are slow: Python dicts are hash tables with O(1) operations. They are one of the most optimized data structures in CPython. For frequency counting, the bottleneck is the Python
forloop overhead, not the dictionary. - Using
list.count()in a loop:[text.count(c) for c in text]runscount()for every character in the string (including duplicates), making it O(n^2). Always iterate overset(text)or use Counter. - Forgetting that Counter returns 0 for missing keys:
Counter(text)['z']returns0, notKeyError. This is different from a regular dict whered['z']would raiseKeyError. - Sorting by frequency incorrectly:
sorted(freq)sorts by keys, not values. Usesorted(freq.items(), key=lambda x: x[1], reverse=True)orCounter.most_common()to sort by frequency. - Unicode normalization: Characters like 'e' and 'e with accent' are different Unicode code points. If you want accent-insensitive counting, normalize with
unicodedata.normalize('NFKD', text)first.
Summary
- Python dictionaries are O(1) for lookup and insertion — they are not slow for frequency counting
collections.Counteris the fastest and most Pythonic choice (C-optimized counting)defaultdict(int)is the second-best option, avoiding explicit key existence checks- Manual
dictwithif/elseor.get()works but is ~2-3x slower than Counter due to Python loop overhead - For very large ASCII strings (1MB+), NumPy's
bincountis the absolute fastest option
Related reading
- Python - Tree traversal question
- Python 3 turn range to a list
- Python add item to the tuple
- Python Convert complex dictionary of strings from Unicode to ASCII
- Python - Speed up an A Star Pathfinding Algorithm
- Python CMA-ES Algorithm to solve user-defined function and constraints
- Python - json without whitespaces
- Python - machine learning

DSA Fundamentals
Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.