Everything Said Twice
An easy Python interview practice problem on DataDriven. Write the Python and run it against test cases, with instant feedback.
- Domain
- Python
- Difficulty
- easy
- Seniority
- L3
- Asked in
- Tata Consultancy Services
Problem
Given text, a raw text field pulled from our event logs, return a dict mapping each word to how many times it appears. The spacing in these fields is uneven: words may be separated by doubled spaces or tabs, and the field may be padded at either end. Words count exactly as written, so differently cased spellings stay separate.
Every word leaves a mark. Count who keeps coming back.
Example 1
Input:
text = "click view click submit view view"
Output:
{"click":2,"view":3,"submit":1}Example 2
Input:
text = "hello"
Output:
{"hello":1}Worked solution and explanation
What this is really testing
Strip the costume and this is a tokenize-and-tally: chop a string into words and count how many times each shows up. Almost everyone gets the counting right. What separates people is one keystroke: text.split() with no argument versus text.split(' ') with a literal space. The two agree on the happy path 'a b c' and diverge the instant the input has a double space, a tab, or a leading blank. Pick the wrong one and you silently seed the dict with an empty-string key that carries a real count. The output is wrong in a way that survives casual eyeballing.
How you get there
Step 1: Split on whitespace, not on a space character
Uneven spacing is the tell in the prompt. No-argument split() collapses runs of spaces, tabs and newlines and strips both ends, so it never manufactures empty tokens. Hardcode split(' ') and you are betting the input is perfectly single-spaced, which real text never is.
Step 2: Tally in one pass
Feed the tokens straight into collections.Counter. It walks them once and increments in C. A hand-rolled counts[word] = counts.get(word, 0) + 1 loop is just as correct, but Counter is the idiom a reviewer expects, and it brings most_common() for the inevitable follow-up.
Step 3: Hand back a plain dict
The signature promises -> dict. Counter is a dict subclass, but wrapping it in dict() matches the contract exactly and won't surprise a caller that checks the concrete type. Empty input needs no special case: ''.split() is [], so the result is {}.
from collections import Counter
def word_counts(text: str) -> dict:
return dict(Counter(text.split()))One pass to split, one pass to count.
- `split(' ')`: the trap
' the the cat '.split(' ')gives['', '', 'the', '', 'the', 'cat', '']. The tally now carries a '' key with count 3 next to 'the' with count 2: a junk key that passes a quick glance.- `split()`: correct
' the the cat '.split()gives['the', 'the', 'cat'], so the tally is{'the': 2, 'cat': 1}. Runs collapse, ends trim, and no empty token ever appears.
Common follow-up questions
- What changes if words should be counted case-insensitively? (`Counter(text.lower().split())`, but `.lower()` allocates a full copy of the string, and you should confirm the prompt really wants case folded.)
- How would you return the top 3 most common words? (`Counter(...).most_common(3)` gives (word, count) tuples in descending order; be ready to say that ties keep first-seen order.)
- How would you handle a 10 GB file that doesn't fit in memory? (Stream it line by line and call `Counter.update(tokens)` per line; memory stays bounded by vocabulary size, not file size.)