Sets and Deduplication
Use sets to model membership, uniqueness, replay protection, intersections, and duplicate detection in real systems.
What you will be able to do
A set answers one question efficiently: have we seen this value before? That question appears everywhere in production software: duplicate events, replayed webhooks, already-sent notifications, selected IDs, unique visitors, fraud signals, autocomplete candidates, and merge pipelines.
A Set Is About Membership, Not Rich Records
A hash map stores key to value. A set stores keys only. If the product needs to know whether an ID exists, a set is enough. If it needs a count, timestamp, status, or payload, use a map. This distinction keeps implementations smaller and answers clearer.
SkillSkore principle
Use a set when uniqueness or membership is the actual requirement. Do not use it when the product needs counts, ordering, or per-key metadata.
Scenario: Webhook Deduplication
A payment provider sends webhooks to your service. Network retries can deliver the same event more than once. If your handler blindly processes every webhook, a customer might receive duplicate emails, duplicate credits, or duplicate fulfillment actions. A set of processed event IDs prevents repeated side effects.
| Requirement | Set role | Production risk |
|---|---|---|
| Ignore duplicate webhook | processedEventIds contains eventId | The set must survive process restarts if side effects are serious. |
| Avoid duplicate notifications | sentNotificationIds contains eventId:userId | Key must include enough scope to avoid suppressing valid sends. |
| Merge search candidates | seenDocumentIds prevents repeated results | Set preserves uniqueness but not ranking by itself. |
| Track unique visitors | visitorIds stores unique identities | Memory and privacy constraints matter. |
Same Pattern in Java, Python, and JavaScript
The following examples return unique events in first-seen order. The set tracks membership. The output list preserves order. This is a common combination: a set for lookup plus a sequence for final presentation.
import java.util.*;
record Event(String id, String payload) {}
class EventDedup {
static List<Event> uniqueInArrivalOrder(List<Event> events) {
Set<String> seen = new HashSet<>();
List<Event> result = new ArrayList<>();
for (Event event : events) {
if (seen.add(event.id())) {
result.add(event);
}
}
return result;
}
}Set vs Map vs Array
| Requirement | Better structure | Reason |
|---|---|---|
| Need to know if ID exists | Set | Membership is the dominant operation. |
| Need metadata per ID | Map | A value must be attached to the key. |
| Need counts per ID | Map/counter | A set loses multiplicity. |
| Need stable display order | Array/list plus set | Array preserves order; set prevents duplicates. |
| Need sorted unique values | Tree set/sort later | Hash sets do not provide sorted order by default. |
Deduplication Design Questions
- What is the identity key: event ID, user ID, normalized email, document ID, or compound key?
- How long must the system remember the key: request lifetime, session, day, billing period, or forever?
- What happens on process restart: can duplicates be tolerated, or must the set be persisted?
- Does deduplication preserve the first item, latest item, highest-priority item, or merged item?
- Can the set grow without bound, and should it use TTL, windowing, batching, or durable storage?
Cost Model and Limits
Set add, contains, and remove are expected O(1) in common hash-set implementations. But every unique key consumes memory. For a small request-local dedup this is trivial. For a streaming pipeline, unbounded sets become memory incidents unless the key lifetime is bounded.
Assessment trap
A set removes duplicates but also removes information. If duplicates carry meaning, such as frequency, repeated failures, demand, or fraud intensity, a set may hide the signal you need.
Interview signalFrequently Asked Interview Questions
These are canonical interview patterns for this topic, phrased as concrete problem statements. They avoid vague theory questions and prepare you for the exact reasoning interviewers expect: invariant, edge cases, complexity, and trade-off.
- Given an integer array, return true if any value appears at least twice.
- Given two arrays, return the unique values that appear in both arrays.
- Given a stream/list of event IDs, process each unique event once while preserving first-seen order.
Production practiceCompany-Style Practice Examples
These are not claimed as exact company-specific questions. They are the interview patterns repeatedly used by product companies to test whether you can move from brute force to a defensible implementation.
| Example | Brute-force approach | Stronger solution | Production notes |
|---|---|---|---|
| Contains duplicate | Compare every pair. | Track seen values in a set and stop at the first repeat. | Expected O(n) time, O(n) memory; set loses duplicate count. |
| Unique intersection | Nested scan and push duplicates. | Build a set from one array, scan the other, and collect results in an output set. | Clarify whether output order matters. |
| Webhook replay protection | Process every event arrival. | Remember processed event IDs in a durable set/index. | Mention TTL, persistence, locking, and side-effect safety. |
Solved modelInterview Question Solutions
Question 1: Contains Duplicate
Given an integer array, return true if any value appears at least twice. The brute-force solution compares every pair. The set solution tracks values already seen and returns as soon as a repeat appears.
import java.util.*;
class ContainsDuplicate {
static boolean containsDuplicate(int[] nums) {
Set<Integer> seen = new HashSet<>();
for (int value : nums) {
if (!seen.add(value)) return true;
}
return false;
}
}Question 2: Unique Intersection of Two Arrays
Given two arrays, return the unique values that appear in both arrays. Build a set from one array, scan the other, and add matches to an output set so duplicates do not repeat in the answer.
import java.util.*;
class ArrayIntersection {
static int[] intersection(int[] a, int[] b) {
Set<Integer> values = new HashSet<>();
for (int value : a) values.add(value);
Set<Integer> result = new HashSet<>();
for (int value : b) {
if (values.contains(value)) result.add(value);
}
int[] output = new int[result.size()];
int i = 0;
for (int value : result) output[i++] = value;
return output;
}
}Question 3: First-Seen Event Deduplication
Given a stream/list of event IDs, process each unique event once while preserving first-seen order. Use a set to remember processed IDs and a list to preserve the order of accepted events. In production, make the set durable if duplicate side effects cannot be tolerated after restart.
import java.util.*;
record Event(String id, String payload) {}
class UniqueEvents {
static List<Event> unique(List<Event> events) {
Set<String> seen = new HashSet<>();
List<Event> result = new ArrayList<>();
for (Event event : events) {
if (seen.add(event.id())) result.add(event);
}
return result;
}
}Solved modelWorked Interview Answer
Return unique events in first-seen order. Use a set for membership and a list for output order. The set answers whether an event ID has appeared; the output list preserves the first accepted event.
import java.util.*;
record Event(String id, String payload) {}
class UniqueEvents {
static List<Event> unique(List<Event> events) {
Set<String> seen = new HashSet<>();
List<Event> result = new ArrayList<>();
for (Event event : events) {
if (seen.add(event.id())) result.add(event);
}
return result;
}
}Hands-on drillTry It Yourself
Practice task
Design deduplication for a webhook handler. Define the key, whether the set is in-memory or durable, how long keys live, and what side effect duplicates would cause.
Failure patternsCommon Mistakes to Avoid
- Using a set when the product actually needs counts or metadata.
- Forgetting that set deduplication may not preserve sorted order.
- Keeping an unbounded set forever in a long-running stream.
- Choosing an identity key that is too broad or too narrow.
- Ignoring restart and distributed-processing behavior for serious side effects.
Execution guardrailQuick-Start Checklist
- Define the membership key.
- Decide whether order matters.
- Decide whether counts or metadata matter.
- Bound the lifetime of stored keys.
- State expected runtime, memory cost, and failure mode.
Recall drillKnowledge Check
| Question | Strong answer |
|---|---|
| What question does a set answer? | Whether a value is a member of the collection. |
| What information does a set discard? | Duplicate count, arrival count, and per-key metadata unless stored elsewhere. |
| Why can sets be risky in streams? | Distinct keys can grow without bound unless lifetime is limited. |
VocabularyKey Terms
| Term | Meaning |
|---|---|
| Membership | Whether a value exists in a collection. |
| Deduplication | Removing or suppressing repeated values according to an identity rule. |
| First-seen order | Preserving the order in which unique values first appeared. |
| TTL | Time to live: how long a remembered key remains valid. |
| Compound key | A key built from multiple fields to represent exact identity. |
Next practiceFurther Reading
- Practice contains-duplicate, intersection, and first-duplicate problems.
- Review idempotency and replay protection in event-driven systems.
- Study Bloom filters later for approximate membership under memory pressure.