Contact dedupe
MediumOnline Assessment
Group contact-book entries that belong to the same person.
Each contact is a string "name|email|phone"; any field may be empty. Two contacts are duplicates if they have the same normalized email or the same normalized phone number. Duplication is transitive: if A duplicates B and B duplicates C, then A, B and C are all in the same group, even if A and C share nothing directly. Names are never used for matching (two different people can have the same name).
Normalization:
- Email. Trim spaces and convert to lowercase. Split at
@; in the part before the@, delete the first+and everything after it (ann+news@x.combecomesann@x.com). If there is no@, or the part before the@is now empty, or the part after the@is empty, the contact has no usable email. - Phone. Keep only the digits. If fewer than 7 digits remain, the contact has no usable phone. Otherwise only the last 10 digits are used (all of them if there are fewer than 10), so
+1 (415) 555-0134and415.555.0134are the same number.
A contact without a usable email or phone simply cannot match through that field.
Input: contacts, a list of strings in the format above.
Output: a list of groups, one for every contact including those that match nobody. Each group is a list of 0-based indices into contacts in ascending order. Order the groups by their smallest index. If contacts is empty, return [].
Example 1
- Input:
- [["Ann|ann@x.com|555-0101","Annie|ANN+news@x.com|","Bob||(555) 0102"]]
- Output:
- [[0,1],[2]]
- Explanation
- Contact 0 and contact 1 normalize to the same email ann@x.com (case is ignored, and "+news" is dropped). Contact 2 has a phone number of its own (5550102) and no email. Groups: [0, 1] and [2].
Example 2
- Input:
- [["A|a@x.com|111 222 3333","B|b@x.com|+1 111 222 3333","C|b+z@x.com|","D|d@x.com|999"]]
- Output:
- [[0,1,2],[3]]
- Explanation
- Contacts 0 and 1 share the phone 1112223333 (only the last 10 digits count). Contacts 1 and 2 share the email b@x.com once "+z" is dropped, so all three are one group even though 0 and 2 have nothing in common directly. Contact 3 has only 3 digits of phone (too short), so it is alone.
Example 3
- Input:
- [["Sam||","Sam||","P|+a@host.com|","Q|+b@host.com|","R|r@h.com|123456","S|r@h.com|"]]
- Output:
- [[0],[1],[2],[3],[4,5]]
- Explanation
- Names never matter, so the two Sams stay apart. The emails "+a@host.com" and "+b@host.com" have an empty local part after dropping the tag, so they are ignored and do not match each other. Contact 4's phone has 6 digits, which is too short. Contacts 4 and 5 share r@h.com.
Constraints
0 <= contacts.length <= 300- Each contact is
"name|email|phone"with exactly two|characters; any field may be empty - Names have no
|; emails have at most one@; phone fields may contain digits, spaces and the characters+ - ( ) .