Learn by reading through in order

Sorting and Searching — sort / find / some / every

Learn sort, which orders an array by a compare function, toSorted, which keeps the original, find and findIndex, which return one match, and some and every.

If you sort a list by writing a for loop that swaps elements, you have to manage both the comparisons and the swaps yourself, every single time. Searching for the one item that matches a condition leads to the same kind of code: a for loop with a break to exit as soon as the item is found.

This article covers sort, which reorders an array, and find, which searches for an element that matches a condition.

Specifying the Order With a Function — sort and Compare Functions

Say you want to display a product list sorted from cheapest to most expensive. An array method handles the sorting, but writing just products.sort() won't sort by price, because you haven't told it what to compare.

You pass sort (a method that reorders an array's elements) a compare function (a function that takes two elements and returns a number). If the two elements it receives are called a and b, a negative return value puts a first and a positive one puts b first. Return a.price - b.price, and you get prices in ascending order.

const products = [
  { name: "Wireless Mouse", price: 2980 },
  { name: "Power Bank", price: 4380 },
  { name: "USB-C Cable", price: 980 },
  { name: "Mouse Pad", price: 2980 },
];

// If the subtraction is negative, a comes first; if positive, b comes first
products.sort((a, b) => a.price - b.price);
console.log(products.map((item) => item.price).join(", "));  // 980, 2980, 2980, 4380

// Check the order of the two items with the same price
console.log(products[1].name, products[2].name);             // Wireless Mouse Mouse Pad

// Flip the subtraction and you get descending order
products.sort((a, b) => b.price - a.price);
console.log(products[0].name);                               // Power Bank
The Number the Compare Function Returns Decides the Order
Compare functiona.price - b.pricea is 980b is 2980a is 2980b is 2980a is 4380b is 980-2000Returns a negative0No difference3400Returns a positivePuts a firstKeeps theoriginal orderPuts b first
The same compare function returns a different number depending on the prices of the two items passed in. Two items with a difference of 0 keep the order they had before sorting.

sort only looks at the sign of the number returned, so -2000 and -1 are treated the same. To also control the order of items with the same price, have the compare function compare another value when the difference is 0.

Sort a marketplace app's listings into the order they'll appear on screen. listings is already declared.

① Sort by the number of characters in the product name, shortest first, and display the product names joined with ", ".

② Sort by price, cheapest first, and display the product names the same way.

③ Sort by price again, but this time order listings with the same price by likes, most first, and display the product names the same way.

(If it runs correctly, an explanation will appear.)

JavaScript / TypeScript Editor

Run code to see output

Calling sort Without Arguments — Default Comparison and toSorted

Say you want to sort an array of time-on-page values, in seconds, from shortest to longest. If you call sort() without a compare function, the result isn't in numeric order: 1180 seconds comes before 25 seconds.

Without a compare function, sort first converts the elements to strings and then compares them character by character. 1180 is treated as "1180" and 25 as "25", so the order is decided by the leading 1 and 2. sort reorders the array it's called on in place, so when you also want to keep the original order, use toSorted (a method that returns a new, sorted array).

const viewSeconds = [1180, 980, 25, 4380];

// Without a compare function, they're compared as strings
console.log(viewSeconds.sort().join(", "));                 // 1180, 25, 4380, 980

// Pass a compare function and they're sorted numerically
console.log(viewSeconds.sort((a, b) => a - b).join(", "));  // 25, 980, 1180, 4380

// toSorted returns a new array and leaves the original unchanged
const stayTimes = [1180, 980, 25, 4380];
console.log(stayTimes.toSorted((a, b) => a - b).join(", "));  // 25, 980, 1180, 4380
console.log(stayTimes.join(", "));                            // 1180, 980, 25, 4380
A Compare Function Changes What Gets Compared
Writesort()Numbers becomestringsCompares 1180, 25from the 1st char1180 staysin frontPass(a, b) => a - bSubtracts themas numbers1180 - 25 ispositive25 comesfirst
The same 1180 and 25 are compared as different kinds of values depending on whether you pass a compare function. The two rows put a different element first.

Once they're strings, "1180" will always come before "25", so pass a compare function when you sort an array of numbers. The second sort in the code above sorts viewSeconds again, after the first call already rearranged it.

How sort and toSorted Affect the Array
viewSeconds.sort(...)Rewrites thesame arrayReturns thatsame arrayOriginal orderis loststayTimes.toSorted(...)Only reads theoriginal arrayReturns anew arrayOriginal orderis kept
What sort returns in the top row is the rearranged viewSeconds itself. Only toSorted creates a new array.

Older Browsers Don't Have toSorted

toSorted was added to the spec in ES2023, and in older browsers that don't support it, the line that calls it throws a TypeError. To make it work in those environments too, call sort on a copy made with spread syntax, as in [...stayTimes].sort((a, b) => a - b).

Sort a list of member IDs and a list of stock counts, and display the results. memberIds and stockCounts are already declared.

① Sort memberIds without passing a compare function, and display it joined with ", ".

② Create a new, sorted array from stockCounts without passing a compare function, and display it the same way.

③ Create a new array from stockCounts sorted from smallest to largest, and display it the same way.

④ Display the first element of stockCounts.

JavaScript / TypeScript Editor

Run code to see output

Getting the One Matching Item — find and findIndex

Say you want to get one reservation by its reservation code. You could use filter, but it returns an array, so you'd have to add [0] to read the first item — and if no reservation matches, you get an empty array back.

find (a method that returns the first element that matches a condition) returns the element itself: the first one for which the callback returns true. When you want its position instead, use findIndex (a method that returns the position of the first element that matches a condition).

const reservations = [
  { code: "RSV-201", room: "Meeting Room A" },
  { code: "RSV-202", room: "Meeting Room B" },
  { code: "RSV-203", room: "Meeting Room C" },
];

// Returns the first element for which the callback returned true
const target = reservations.find((item) => item.code === "RSV-202");
console.log(target.room);  // Meeting Room B

// Use findIndex when you want the position
console.log(reservations.findIndex((item) => item.code === "RSV-202"));  // 1

// When no reservation matches
console.log(reservations.find((item) => item.code === "RSV-999"));       // undefined
console.log(reservations.findIndex((item) => item.code === "RSV-999"));  // -1
The Calls Stop As Soon As a Match Is Found
1st: RSV-201returns falseMoves on tothe next one2nd: RSV-202returns trueThis element isfind's result3rd: RSV-203never checkedChecking stopsafter 2 items
Once the callback returns true for the second item, it's never called for the third. The earlier the match, the fewer calls are made.

find returns only the first matching item, so it can't collect every match when there are several. Use filter, which returns an array, when you need all of them, and find when one is enough.

You Get undefined When Nothing Is Found

If you read the value find returned directly, as in target.room, it throws TypeError: Cannot read properties of undefined (reading 'room') when no element matched. Check it with if (target) before reading it.

Look up coupons on offer by condition. coupons is already declared, and a coupon whose expired property is true has expired.

① Display the discount rate of the coupon with the code MEMBER15.

② Display the position (counted from 0) of the expired coupon.

③ Display the code of the first coupon that hasn't expired.

④ Search for the coupon with the code AUTUMN30, and display its discount rate if it exists, or "Not found" if it doesn't.

JavaScript / TypeScript Editor

Run code to see output

Checking the Whole Array for true or false — some and every

Say you want to decide from stock levels whether an order's items can all ship together. You could collect the out-of-stock items with filter and count them, but what you want isn't an array — it's a single answer, true or false.

some (a method that returns true if at least one element matches the condition) and every (a method that returns true if every element matches the condition) return a boolean, not an element. You can use them directly as an if condition.

const orderItems = [
  { name: "Refill Bottle", stock: 12 },
  { name: "Hand Soap", stock: 0 },
  { name: "Foaming Net", stock: 5 },
];

// true if at least one matches
console.log(orderItems.some((item) => item.stock === 0));   // true

// true only if all of them match
console.log(orderItems.every((item) => item.stock > 0));    // false

// On an empty array, some is false and every is true
console.log([].some((item) => item.stock > 0));             // false
console.log([].every((item) => item.stock > 0));            // true
Where some and every Stop Checking
Call some:look for stock 01st: 12returns false2nd: 0returns trueReturns true,skips the restCall every:all in stock?1st: 12returns true2nd: 0returns falseReturns false,skips the rest
Both some and every have their answer by the second item, which has 0 in stock. every finishes as soon as it finds an element that doesn't match.

On an empty array, no element matches the condition, so some is false, and no element fails the condition either, so every is true. The table below sums up what the four search methods in this article return.

MethodReturnsWhen no element matches
findThe first matching element itselfundefined
findIndexThe position of the first matching element-1
sometrue if at least one matchesfalse
everytrue if all matchfalse (true for an empty array)

Check whether every learner in an online course can get a certificate of completion, based on assignments submitted and attendance rate. learners is already declared.

① Display whether every learner has submitted at least one assignment.

② Display whether any learner has 0 submissions.

③ Display the name of the learner with 0 submissions.

④ Display whether every learner's attendance rate is 80% or higher.

JavaScript / TypeScript Editor

Run code to see output
QUIZ

Knowledge Check

Answer each question one by one.

Q1When the compare function returns a negative value, which element does sort put first?

Q2If you call sort() on [1180, 980, 25] without a compare function, what order do you get?

Q3Which method do you use to check, as a single boolean, whether every stock count is 1 or more?