// 1. Clean each name: trim whitespace, convert to title case ("Alice Chen")
const sanName = (name) => name.split(" ").filter(Boolean).map((w) => w[0].toUpperCase() + w.slice(1).toLowerCase()).join(" ");
// 2. Remove duplicates (case-insensitive comparison)
const dedupNames = (names) => {
const seen = new Set();
return names.filter((n) => {
const key = n.toLowerCase();
if (seen.has(key)) return false;
seen.add(key);
return true;
});
};
// 3. Sort alphabetically
const sortName = (names) => [...names].sort((a, b) => a.localeCompare(b));
// +extra
const flagDups = (names) => {
const counts = {};
names.forEach((n) => (counts[n] = (counts[n] || 0) + 1));
return Object.keys(counts).filter((n) => counts[n] > 1);
};
// test
const rawNames = [
" alice Chen", "BOB martinez ", "alice chen",
" Carlos ruiz", "Diana WONG", "bob Martinez",
" eva Kim ", "Carlos Ruiz"
];
const result = sortName(dedupNames(rawNames.map(sanName)));
console.assert(
JSON.stringify(result) === JSON.stringify(["Alice Chen", "Bob Martinez", "Carlos Ruiz", "Diana Wong", "Eva Kim"]),
"dedup/sort failed", result
);
console.assert(
JSON.stringify(flagDups(rawNames.map(sanName))) === JSON.stringify(["Alice Chen", "Bob Martinez", "Carlos Ruiz"]),
"flagDups failed"
);
Ly8gMS4gQ2xlYW4gZWFjaCBuYW1lOiB0cmltIHdoaXRlc3BhY2UsIGNvbnZlcnQgdG8gdGl0bGUgY2FzZSAoIkFsaWNlIENoZW4iKQpjb25zdCBzYW5OYW1lID0gKG5hbWUpID0+IG5hbWUuc3BsaXQoIiAiKS5maWx0ZXIoQm9vbGVhbikubWFwKCh3KSA9PiB3WzBdLnRvVXBwZXJDYXNlKCkgKyB3LnNsaWNlKDEpLnRvTG93ZXJDYXNlKCkpLmpvaW4oIiAiKTsKCi8vIDIuIFJlbW92ZSBkdXBsaWNhdGVzIChjYXNlLWluc2Vuc2l0aXZlIGNvbXBhcmlzb24pCmNvbnN0IGRlZHVwTmFtZXMgPSAobmFtZXMpID0+IHsKICAgIGNvbnN0IHNlZW4gPSBuZXcgU2V0KCk7CiAgICByZXR1cm4gbmFtZXMuZmlsdGVyKChuKSA9PiB7CiAgICAgICAgY29uc3Qga2V5ID0gbi50b0xvd2VyQ2FzZSgpOwogICAgICAgIGlmIChzZWVuLmhhcyhrZXkpKSByZXR1cm4gZmFsc2U7CiAgICAgICAgc2Vlbi5hZGQoa2V5KTsKICAgICAgICByZXR1cm4gdHJ1ZTsKICAgIH0pOwp9OwoKLy8gMy4gU29ydCBhbHBoYWJldGljYWxseQpjb25zdCBzb3J0TmFtZSA9IChuYW1lcykgPT4gWy4uLm5hbWVzXS5zb3J0KChhLCBiKSA9PiBhLmxvY2FsZUNvbXBhcmUoYikpOwoKLy8gK2V4dHJhCmNvbnN0IGZsYWdEdXBzID0gKG5hbWVzKSA9PiB7CiAgICBjb25zdCBjb3VudHMgPSB7fTsKICAgIG5hbWVzLmZvckVhY2goKG4pID0+IChjb3VudHNbbl0gPSAoY291bnRzW25dIHx8IDApICsgMSkpOwogICAgcmV0dXJuIE9iamVjdC5rZXlzKGNvdW50cykuZmlsdGVyKChuKSA9PiBjb3VudHNbbl0gPiAxKTsKfTsKCi8vIHRlc3QKY29uc3QgcmF3TmFtZXMgPSBbCiAgICAiICBhbGljZSBDaGVuIiwgIkJPQiBtYXJ0aW5leiAiLCAiYWxpY2UgY2hlbiIsCiAgICAiIENhcmxvcyBydWl6IiwgIkRpYW5hIFdPTkciLCAiYm9iIE1hcnRpbmV6IiwKICAgICIgIGV2YSBLaW0gIiwgIkNhcmxvcyBSdWl6IgpdOwoKY29uc3QgcmVzdWx0ID0gc29ydE5hbWUoZGVkdXBOYW1lcyhyYXdOYW1lcy5tYXAoc2FuTmFtZSkpKTsKCmNvbnNvbGUuYXNzZXJ0KAogICAgSlNPTi5zdHJpbmdpZnkocmVzdWx0KSA9PT0gSlNPTi5zdHJpbmdpZnkoWyJBbGljZSBDaGVuIiwgIkJvYiBNYXJ0aW5leiIsICJDYXJsb3MgUnVpeiIsICJEaWFuYSBXb25nIiwgIkV2YSBLaW0iXSksCiAgICAiZGVkdXAvc29ydCBmYWlsZWQiLCByZXN1bHQKKTsKCmNvbnNvbGUuYXNzZXJ0KAogICAgSlNPTi5zdHJpbmdpZnkoZmxhZ0R1cHMocmF3TmFtZXMubWFwKHNhbk5hbWUpKSkgPT09IEpTT04uc3RyaW5naWZ5KFsiQWxpY2UgQ2hlbiIsICJCb2IgTWFydGluZXoiLCAiQ2FybG9zIFJ1aXoiXSksCiAgICAiZmxhZ0R1cHMgZmFpbGVkIgopOwoK