QA coding round: collections and maps
Updated 2026-11-13 · 6 min read
Practise counting, grouping, deduplication and response comparison with Python and Node examples, plus explicitly unverified Java code. Includes answer structure, edge cases and follow-up practice.
A useful collection choice follows the question: do you need order, multiplicity, lookup or grouping? These exercises model test-result processing and fake API responses. Python blocks were executed with Python 3.14.4 and the JavaScript block with Node v24.22.2.
Choose a representation
1. When would you use a list, set or map?
Use a list when positions or repeats matter, a set for distinct membership, and a map to associate a key with data. A list of failed test IDs preserves repeated attempts; a set answers which tests failed at least once; a map can associate each ID with its attempts. These are different questions, so converting to a set too early can throw away evidence.
2. How do you count results by status?
Count statuses rather than writing one conditional variable for every possible label. Keep unknown statuses visible so a newly introduced blocked result is not silently counted as passed. Decide separately whether unknown labels should cause validation failure.
from collections import Counter
statuses = ['passed', 'failed', 'passed', 'blocked']
counts = Counter(statuses)
assert counts == {'passed': 2, 'failed': 1, 'blocked': 1}
assert counts['skipped'] == 0
assert sum(counts.values()) == len(statuses)
3. How would the same count look in Java?
The map associates each status with its current count; merge supplies one for a new key or combines with the existing value. Do not rely on HashMap iteration order when printing the report. This illustrative block is unverified Java, not an executed example.
import java.util.HashMap;
import java.util.Map;
class StatusCounts {
public static void main(String[] args) {
Map<String, Integer> counts = new HashMap<>();
for (String status : new String[]{"passed", "failed", "passed"}) {
counts.merge(status, 1, Integer::sum);
}
if (!Integer.valueOf(2).equals(counts.get("passed"))) {
throw new AssertionError("incorrect passed count");
}
}
}
4. Why does Java key design matter?
A key must continue to behave consistently for equality while it is stored. Mutating a field used for equality can make later lookups unreliable. For a test report, a stable immutable ID is a clearer key than a mutable test-result object; two results with the same display name may still be different tests.
Group, index and compare
5. How do you group failures by component?
Store a list per component rather than overwriting the earlier failure. This example excludes passed results deliberately and preserves encounter order inside each group. Add a component with no failures only if the report contract requires explicit empty groups.
from collections import defaultdict
results = [('cart', 'C01', 'failed'), ('cart', 'C02', 'failed'),
('login', 'L01', 'passed')]
failures = defaultdict(list)
for component, test_id, status in results:
if status == 'failed':
failures[component].append(test_id)
assert dict(failures) == {'cart': ['C01', 'C02']}
6. How do you index an API response without hiding duplicate IDs?
A direct assignment overwrites earlier rows with the same ID. Detect the collision first if uniqueness is part of the API contract. The returned index then supports repeated lookups, but constructing it is worthwhile only if the response size and lookup workload justify the extra memory.
def index_by_id(rows):
result = {}
for row in rows:
key = row['id']
if key in result:
raise ValueError('duplicate id')
result[key] = row
return result
assert index_by_id([{'id': 'P01'}]) == {'P01': {'id': 'P01'}}
try:
index_by_id([{'id': 'P01'}, {'id': 'P01'}])
except ValueError:
pass
else:
raise AssertionError('duplicate was hidden')
7. How do you compare unordered responses that allow duplicates?
Compare frequency tables for hashable values. Sorting can also work when values are mutually comparable, but neither approach defines how to compare arbitrary nested JSON objects. Agree on a stable projection, such as an ID plus version, before reducing records to keys.
from collections import Counter
assert Counter(['P01', 'P02', 'P01']) == Counter(['P01', 'P01', 'P02'])
assert Counter(['P01', 'P01']) != Counter(['P01'])
8. How do you report missing and unexpected IDs?
Compute differences in both directions. Reporting only missing IDs overlooks extra records returned because a filter failed. This exercise assumes unique IDs; add a separate duplicate check before converting to sets if duplicate rows are defects.
expected, actual = {'P01', 'P02'}, {'P02', 'P03'}
assert expected - actual == {'P01'}
assert actual - expected == {'P03'}
assert expected & actual == {'P02'}
9. How does JavaScript Map distinguish an absent key from undefined?
A lookup alone is insufficient because a stored value can itself be undefined. Use has when presence matters. Object keys are compared by identity here, so two separate objects with the same fields are distinct keys; prefer stable scalar IDs for response indexing.
const values = new Map([['P01', undefined]]);
if (!values.has('P01') || values.has('P02')) throw new Error('presence check');
if (values.get('P01') !== values.get('P02')) throw new Error('both are undefined');
const first = { id: 'P01' };
values.set(first, 'saved');
if (values.get({ id: 'P01' }) !== undefined) throw new Error('identity check');
if (values.get(first) !== 'saved') throw new Error('same object must match');
Likely follow-up: Would serializing objects make safe keys? Only with a defined canonical representation. Ordinary serialization is not a substitute for deciding record identity.
10. How do you merge retry results without losing the initial failure?
Keep the attempt history as a list keyed by stable test ID, then derive the final status. Overwriting failed with passed discards evidence of instability. Include attempt number and build identity in a real report so attempts from different builds are not accidentally combined.
11. Is a shared HashMap safe for parallel tests?
Java HashMap is not synchronized. More importantly, replacing the container does not automatically make a multi-step read-modify-write workflow correct. Prefer isolated per-test state, then aggregate completed results in a controlled stage; use concurrency-aware operations when shared updates are truly required and verify them separately.
12. What should you say about complexity?
Separate lookup cost, building the index and generating ordered output. Expected constant-time hash lookup does not make a loop over every result constant-time. For an error summary, counting is expected O(n), but sorting distinct keys introduces additional work; state assumptions rather than promising a timing benchmark.
Practise it
Build a report from five fake attempts containing a repeated test ID, an unknown status and a retry pass. Explain what data your representation preserves. Then use ShopLite product IDs to practise missing, extra and duplicate response checks.
Quick answers
Which language should I use in the interview?
Use the requested language. These Python and Node exercises verify the algorithms, not the Java translation.
Is map iteration always insertion ordered?
No. Order depends on the implementation: Java HashMap does not guarantee it, while JavaScript Map preserves insertion order.
Sources
Want a project you can show in interviews?
The portfolio project kit walks you through testing a deliberately buggy app with Selenium or Playwright and API tests, then explaining it. The app itself is free.
