Filter Contacts by Email Domain
Reported by candidates from Stripe's online assessment. Pattern, common pitfall, and the honest play if you blank under the timer.
The mistake that sinks most first attempts at this Stripe OA question, reported in January 2026, is treating it like a simple endswith check. It's a string parsing problem with a pile of edge cases. You get contact rows shaped like name,email,phone and a requested domain, and you return the original rows whose email domain matches exactly. Case doesn't matter for the domain, order does, and malformed rows get dropped silently. If you blank on the validation order, StealthCoder is the invisible safety net running during the live OA. But the logic is short once you see it.
The problem
You are given contact rows and a requested email domain. Each contact row has the form name,email,phone. Return every original contact row whose email has exactly one @, a non-empty local part, and a domain equal to the requested domain using case-insensitive comparison. The requested domain may optionally begin with @. Preserve the contacts' input order. Ignore malformed contact rows and malformed email addresses. Function filterContactsByDomain(contacts: String[], domain: String) → String[] Examples Example 1 contacts = ["Alice,alice@example.com,111","Bob,bob@other.com,222","Cara,cara@EXAMPLE.COM,333"] domain = "example.com" return = ["Alice,alice@example.com,111","Cara,cara@EXAMPLE.COM,333"] Alice and Cara have the requested domain. Domain comparison is case-insensitive, and their original rows and order are preserved. Example 2 contacts = ["A,a@shop.io,1","B,b@sub.shop.io,2","C,invalid,3"] domain = "@shop.io" return = ["A,a@shop.io,1"] The optional leading @ is ignored. A subdomain is not an exact match, and the malformed email is ignored. Example 3 contacts = ["A,@example.com,1","B,b@@example.com,2","C,c@example.org,3"] domain = "example.com" return = [] The first email has an empty local part, the second has two @ characters, and the third uses another domain. Constraints 0 <= contacts.length <= 100000. Every contact string has length at most 500. A well-formed contact row contains exactly two commas; its fields do not contain commas. domain is non-empty after removing one optional leading @ and contains no whitespace, comma, or @. Email local parts and domains are compared without trimming; only domain letter case is ignored.
Reported by candidates. Source: FastPrep
Pattern and pitfall
The pattern is plain string parsing plus a single pass filter. Normalize the requested domain first: strip one leading @, then lowercase it. For each row, split on commas and require exactly three fields. Then check the email: exactly one @, a non-empty local part, and a lowercased domain that equals the target. Use equality, never endswith, or sub.shop.io sneaks through. Return the original row string, not a rebuilt one, and keep input order by appending as you go. The pitfalls are counting @ characters wrong, forgetting the empty local part like @example.com, and lowercasing the whole email instead of just the domain. Don't trim anything. Runs in O(n * 500), which is fine for 100000 rows. If you freeze under the clock, StealthCoder can hand you the clean version during the live OA, but write the checks in this order and you won't need it.
The honest play: practice the pattern, and have StealthCoder ready for the one you didn't see coming.
You can drill Filter Contacts by Email Domain cold, or you can hedge it. StealthCoder runs invisibly during screen share and surfaces a working solution in under 2 seconds. The proctor sees the IDE. They don't see what's behind it. Built for the candidate who saw this exact problem leak two days before his OA and wondered if anyone had a play.
Get StealthCoderRelated leaked OAs
You've seen the question.
Make sure you actually pass Stripe's OA.
Stripe reuses patterns across OAs. Built for the candidate who saw this exact problem leak two days before his OA and wondered if anyone had a play. Works on HackerRank, CodeSignal, CoderPad, and Karat.
Filter Contacts by Email Domain FAQ
What's the trick in the Stripe contact domain filter?+
Exact equality on the domain after normalizing. Strip one optional leading @ from the requested domain, lowercase it, then compare against the lowercased part after the single @ in each email. Using endswith lets subdomains like sub.shop.io match wrongly, which is the classic failure.
How do I validate a malformed contact row?+
Split the row on commas and require exactly three parts. If the count is off, skip it. Then validate the email separately: count @ characters and require exactly one, with text before it. Anything failing either check gets ignored, not raised as an error.
Should I lowercase the whole email or just the domain?+
Just the domain, and only for comparison. The local part is compared without case folding or trimming per the constraints, though here you only check that it's non-empty. Always return the original untouched row string in the output.
How hard is this question really?+
Easy on algorithm, annoying on details. There's no data structure to pick, just one pass. Most failed attempts come from missed edge cases like b@@example.com, an empty local part, or the leading @ on the domain. Test the three given examples by hand.
How do I prepare for this in 48 hours?+
Write a few string parsing filters from scratch and practice listing edge cases before coding. Split, count, check empties, compare normalized values. Then run your solution against malformed inputs: missing commas, extra commas, no @, two @, and an empty contacts array.