Back to DSA & Algorithms
DSA & Algorithms
easy
mid

How would you return an array of sorted unique elements from an input array?

Dedupe with a Set, then sort. One-liner: [...new Set(arr)].sort((a,b)=>a-b). The catch interviewers test: default .sort() is lexicographic, so you MUST pass a numeric comparator for numbers.

3 min read·~8 min to think through

Two operations: dedupe then sort. The whole question hinges on one gotcha.

The solution

js
function sortedUnique(arr) {
  return [...new Set(arr)].sort((a, b) => a - b);
}
sortedUnique([3, 1, 2, 3, 1]); // [1, 2, 3]
  • new Set(arr) removes duplicates in O(n) — Set keeps only distinct values.
  • [...set] spreads it back to an array.
  • .sort((a, b) => a - b) sorts numerically, ascending.

The gotcha interviewers are actually testing

Array.prototype.sort() with no comparator sorts elements as strings:

js
[10, 9, 1, 100].sort();            // [1, 10, 100, 9]  ❌ lexicographic!
[10, 9, 1, 100].sort((a, b) => a - b); // [1, 9, 10, 100] ✅

Forgetting the comparator on numeric input is the #1 mistake. Always pass (a, b) => a - b.

Without Set (if asked)

js
function sortedUnique(arr) {
  const seen = {};
  const out = [];
  for (const x of arr) {
    if (!seen[x]) { seen[x] = true; out.push(x); }
  }
  return out.sort((a, b) => a - b);
}

Or sort first, then filter elements equal to their predecessor.

Other talking points

  • .sort() mutates the array in place and returns it — spreading into a new array first avoids mutating the caller's input.
  • Mixed types / NaNa - b produces NaN for non-numbers; clarify the input contract.
  • Strings — for string input, .sort() with no comparator (or localeCompare for locale-correct order) is actually correct.
  • Complexity — O(n) dedupe + O(n log n) sort = O(n log n).

The framing

"[...new Set(arr)].sort((a, b) => a - b) — Set for O(n) dedupe, sort for O(n log n). The thing I'd call out explicitly is the comparator: bare .sort() is lexicographic, so [10, 9].sort() gives [10, 9]. And since sort mutates, I spread into a fresh array so I don't clobber the caller's input."

Follow-up questions

  • Why does [10, 9, 1].sort() not sort numerically?
  • How would you do this without Set?
  • Does .sort() mutate the original array?
  • How would you sort an array of objects by a property?

Common mistakes

  • Calling .sort() with no comparator on numbers — lexicographic order.
  • Mutating the caller's array because sort() is in-place.
  • Assuming Set preserves a sorted order — it preserves insertion order.
  • Not clarifying the input type (numbers vs strings vs mixed).

Performance considerations

  • O(n) for the Set dedupe plus O(n log n) for the sort = O(n log n) overall, O(n) extra space. Fine for typical inputs; for huge arrays of small integers, a counting/bucket sort could beat it.

Edge cases

  • Empty array — returns [].
  • Already sorted or all-duplicate input.
  • NaN values — never equal to themselves; Set keeps one NaN but comparator breaks.
  • Mixed types or objects — Set dedupes by reference, not value.

Real-world examples

  • Deduping and ordering tag lists or filter options for a UI dropdown.
  • Normalizing IDs before a batch request.

Senior engineer discussion

Seniors write the one-liner instantly but explicitly flag the lexicographic-sort trap and the in-place mutation, and ask about the input contract (numbers vs strings, NaN, objects) before committing to a comparator.

Related questions