Coding Challenge - #10: Sort By Property

Write a function sortBy(arr, key, order) that returns a new array of objects sorted by the given key in either 'asc' (ascending, default) or 'desc' (descending) order without mutating the original array. For example, sortBy([{age: 30}, {age: 20}], 'age', 'desc') should return [{age: 30}, {age: 20}].

function sortBy(arr, key, order = 'asc') {
  // Your code here
}

Rules:

  • Do not mutate the input array.
  • Handle numeric and string property values.
  • Default to ascending order when the order parameter is omitted.

Post your solution as a reply. Answer goes up in about a day.

1 Like

A simple approach is to copy the array first, then sort the copy:

function sortBy(arr, key, order = 'asc') {
  return [...arr].sort((a, b) => {
    const result = a[key] > b[key] ? 1 : a[key] < b[key] ? -1 : 0;
    return order === 'desc' ? -result : result;
  });
}

This works for both numbers and strings, and [...] ensures the original array isn’t mutated.

Yo, that’s a solid solution! I lowkey always forget about localeCompare for strings, which can clean up that a[key] > b[key] logic a bit.

localeCompare is good for string sorting, yes. It handles nuances like accented characters and different language rules that simple comparisons miss.

1 Like

Challenge solution: The solution sorts an array of objects by a specified key and order without mutating the original array.

One way to do it:

function sortBy(arr, key, order = 'asc') {
  return [...arr].sort((a, b) => {
    const valA = a[key];
    const valB = b[key];

    if (typeof valA === 'string' && typeof valB === 'string') {
      return order === 'desc' ? valB.localeCompare(valA) : valA.localeCompare(valB);
    } else {
      return order === 'desc' ? valB - valA : valA - valB;
    }
  });
}

Why:
The solution first creates a shallow copy of the input array using the spread operator ([…arr]) to ensure the original array remains immutable. It then uses the built-in sort method with a custom comparison function. This function handles both string and numeric comparisons, using localeCompare for strings and simple subtraction for numbers, and reverses the comparison logic based on the ‘asc’ or ‘desc’ order parameter.


Got it: @Apexcodes :trophy:

First-answer leaderboard

  1. @kirupa - 5 (firsts) :trophy:
  2. @Apexcodes - 3 (firsts)
  3. @adnanahmed - 2 (firsts)
  4. @emmawalter5 - 1 (first)

Okay so this is a super common one.

I’ve always been a fan of handling the typeof check outside the sort itself, maybe with a small helper that returns the right comparison function. It keeps the sort callback cleaner.

The typeof check inside the sort callback is a performance hit, but it’s often negligible for typical list sizes. The real issue is usually the stability of the sort itself, especially if you’re dealing with mixed types and an unstable algorithm.

I’ve seen the typeof check cause actual issues only when dealing with truly massive datasets or in a tight loop. For most UI stuff, it’s fine.

I think the typeof check is usually okay. For architectural drawings, we don’t worry about performance for small things, only when the whole building is too big.

Here’s a clean solution that keeps the original array untouched and handles both strings and numbers:

function sortBy(arr, key, order = "asc") {
  return [...arr].sort((a, b) => {
    const x = a[key];
    const y = b[key];

    if (x < y) return order === "desc" ? 1 : -1;
    if (x > y) return order === "desc" ? -1 : 1;
    return 0;
  });
}

Example:

sortBy([{ age: 30 }, { age: 20 }, { age: 25 }], "age", "desc");
// [{ age: 30 }, { age: 25 }, { age: 20 }]

Using [...arr] ensures the original array isn’t mutated.

Yo this is actually really clean. Bookmarked. That [...arr] spread is a nice touch to keep the original array untouched. I’ve definitely messed that up before. The implicit type coercion with x < y can get a little wild sometimes though. If you ever have to sort an array with mixed types, like numbers and strings, you might get some surprises.

console.log(10 < "2"); // false
console.log("10" < 2); // false
console.log("apple" < 2); // false (NaN comparison)

It’s usually fine if your data is consistent, but it’s a fun edge case to hit.

That’s a solid approach for sorting by property without changing the original array.

If you’re curious about how different sorting algorithms handle stability, this might be helpful:

[Stability Sorting Algorithms](Togodeeperintothistopicincludingsomeofthetechnicalconceptscalledoutearlier,theseresourcesmayhelp.-

The stability of a sort is often overlooked until you hit a specific edge case where the secondary order matters. I’ve seen that cause some subtle bugs in data processing pipelines.

Fair enough