Skip to content
  • Searching, Sorting & Flattening · JavaScript

Searching, Sorting & Flattening

LearnViaNotes @learnvianotes· 3 min read

Find things, test things, sort things (carefully!) and flatten nested arrays — plus the ES2023 non-mutating copies.

Finding and testing

MethodReturnsStops early?
find(fn) / findLast(fn)First / last matching element or undefinedYes
findIndex(fn) / findLastIndex(fn)Index or -1Yes
indexOf(x) / lastIndexOf(x)Index via === or -1Yes
includes(x)Boolean (finds NaN)Yes
some(fn)true if any passesYes, on first true
every(fn)true if all pass (true for [])Yes, on first false
JavaScript
const users = [
  { id: 1, name: "Asha", admin: false },
  { id: 2, name: "Ravi", admin: true },
  { id: 3, name: "Mei", admin: true },
];
console.log(users.find((u) => u.admin).name, users.findLast((u) => u.admin).name);
console.log(users.findIndex((u) => u.id === 3), users.find((u) => u.id === 9));
console.log(users.some((u) => u.admin), users.every((u) => u.admin));
console.log([].every((x) => x > 100), [].some((x) => x > 100));
console.log([1, 2, NaN].includes(NaN), [1, 2, NaN].indexOf(NaN));
Output
Ravi Mei
2 undefined
true false
true false
true -1

Sorting — the big pitfall

JavaScript
const nums = [10, 1, 5, 100, 25];
console.log([...nums].sort());                 // compares as STRINGS
console.log([...nums].sort((a, b) => a - b));  // numeric ascending
console.log([...nums].sort((a, b) => b - a));  // descending
Output
[ 1, 10, 100, 25, 5 ]
[ 1, 5, 10, 25, 100 ]
[ 100, 25, 10, 5, 1 ]

The comparator returns a negative number if a goes first, positive if b goes first, 0 to keep order. Since ES2019 the sort is stable, so equal items keep their relative order — which lets you sort by several keys.

JavaScript
const people = [
  { name: "Zoe", dept: "HR", age: 30 },
  { name: "adam", dept: "Eng", age: 25 },
  { name: "Émile", dept: "Eng", age: 35 },
  { name: "Bob", dept: "HR", age: 25 },
];
const byDeptThenAge = people.toSorted(
  (a, b) => a.dept.localeCompare(b.dept) || a.age - b.age
);
console.log(byDeptThenAge.map((p) => `${p.dept}:${p.name}`).join(" "));
const names = people.map((p) => p.name);
console.log(names.toSorted());
console.log(names.toSorted((a, b) => a.localeCompare(b)));
console.log(people[0].name);   // original untouched by toSorted
Output
Eng:adam Eng:Émile HR:Bob HR:Zoe
[ 'Bob', 'Zoe', 'adam', 'Émile' ]
[ 'adam', 'Bob', 'Émile', 'Zoe' ]
Zoe

Mutating vs copying (ES2023)

MutatesNon-mutating copy
sort(fn)toSorted(fn)
reverse()toReversed()
splice(i, n, …)toSpliced(i, n, …)
arr[i] = varr.with(i, v)
fill, copyWithin, push, pop, shift, unshiftspread / slice / concat

Flattening

JavaScript
const nested = [1, [2, [3, [4, [5]]]]];
console.log(nested.flat());
console.log(nested.flat(2));
console.log(nested.flat(Infinity));
Output
[ 1, 2, [ 3, [ 4, [Array] ] ] ]
[ 1, 2, 3, [ 4, [ 5 ] ] ]
[ 1, 2, 3, 4, 5 ]

Useful one-liners

JavaScript
const arr = [3, 1, 3, 2, 1];
console.log([...new Set(arr)]);                                  // unique
console.log(Math.max(...arr), arr.reduce((a, b) => a + b, 0));   // max, sum
const chunk = (a, n) => Array.from({ length: Math.ceil(a.length / n) }, (_, i) => a.slice(i * n, i * n + n));
console.log(chunk([1, 2, 3, 4, 5], 2));
const zip = (a, b) => a.map((x, i) => [x, b[i]]);
console.log(zip(["a", "b"], [1, 2]));
console.log([1, 2, 3, 4].filter((x) => [2, 4, 6].includes(x)));  // intersection
Output
[ 3, 1, 2 ]
3 10
[ [ 1, 2 ], [ 3, 4 ], [ 5 ] ]
[ [ 'a', 1 ], [ 'b', 2 ] ]
[ 2, 4 ]

Why does [10, 1, 5].sort() return [1, 10, 5]?

find vs filter?

Free for students and teachers

Write notes like this one

Cards for every idea, quizzes and flashcards, read aloud — on the web and your phone.

Something wrong with this note? Open it to report