Skip to main content

Practice JavaScript Arrays

Six JavaScript array drills for a browser console or a Scrimba scrim, no setup needed: map/filter/reduce, dedup, flatten, a non-mutating sort, a group-by, and a two-array join from junior interviews. Each ships with starting code, an expected result, and a full solution, for anyone who can write array.map(x => x * 2) but freezes on real data.

Before you start​

You need basic JavaScript: variables, arrow functions, and array.method() syntax. If reduce is still fuzzy, open Learn JavaScript (opens in a new tab) (free) alongside this page, or start with the Learn JavaScript course page. A scrim doubles as a scratchpad: pause, edit the visible code, and run to test a guess, no card needed for free courses. Dismiss the one-time 20% banner if it appears. Arrays arrive in its Blackjack module (2.7 hrs, 55 scrims): indexes, push and pop, and a for loop rendering each card.

Drills​

Drill 1: map, filter, and reduce together​

Take a list of prices, apply 8% tax, keep only the ones over 20 after tax, then total what's left.

const prices = [12, 45, 8, 99, 23, 60];

// map, filter, reduce

What you should see: one number, the sum of the taxed prices above 20.

Solution
const withTax = prices.map((price) => price * 1.08);
const overTwenty = withTax.filter((price) => price > 20);
const total = overTwenty.reduce((sum, price) => sum + price, 0);

console.log(total);

map and filter each return a new array, so prices never changes. The common mistake is skipping the 0 starting value in reduce: without it, the first element becomes the accumulator, breaking once you reduce into an object.

Drill 2: remove duplicates while keeping order​

Given a list of tags with repeats, return a new array with each tag appearing once, order preserved.

const tags = ['react', 'javascript', 'css', 'react', 'html', 'javascript'];

// remove duplicates, keep order

What you should see: ['react', 'javascript', 'css', 'html'].

Solution
const uniqueTags = [...new Set(tags)];

A Set only stores unique values and remembers insertion order, so spreading it back into an array gives you what you want in one line. The trap: deduping with a for loop that calls splice while iterating shifts every later index down, skipping the item right after each duplicate.

Drill 3: flatten nested arrays​

Some items in this array are arrays themselves, nested more than one level deep. Return a single flat array.

const nested = [[1, 2], [3, [4, 5]], [6]];

// flatten to: [1, 2, 3, 4, 5, 6]

What you should see: [1, 2, 3, 4, 5, 6].

Solution
const flat = nested.flat(Infinity);

flat() takes a depth argument, default 1, so plain nested.flat() would leave [4, 5] nested inside the second element. Infinity flattens however deep the data goes, safer than guessing a fixed depth.

Drill 4: sort objects by a key without mutating the original​

Sort a list of products by price, cheapest first, without changing the order of the original products array.

const products = [
{ name: 'Keyboard', price: 45 },
{ name: 'Monitor', price: 199 },
{ name: 'Mouse', price: 25 },
];

// return a NEW sorted array; products must stay unchanged

What you should see: a new array ordered Mouse, Keyboard, Monitor, while products still logs Keyboard, Monitor, Mouse.

Solution
const sortedByPrice = [...products].sort((a, b) => a.price - b.price);

sort() mutates the array it's called on and returns that reference, so products.sort(...) would quietly reorder your original data too. Spread products into a new array first, then sort the copy: the most common mutation bug in array interviews.

Drill 5: group items into an object with reduce​

Group a list of people into an object keyed by department, so each key holds an array of the people in it.

const people = [
{ name: 'Ana', dept: 'Engineering' },
{ name: 'Ben', dept: 'Sales' },
{ name: 'Cleo', dept: 'Engineering' },
{ name: 'Dev', dept: 'Sales' },
{ name: 'Eve', dept: 'Marketing' },
];

// group into: { Engineering: [...], Sales: [...], Marketing: [...] }

What you should see: an object with three keys, each holding the matching person objects.

Solution
const byDept = people.reduce((groups, person) => {
const key = person.dept;
if (!groups[key]) {
groups[key] = [];
}
groups[key].push(person);
return groups;
}, {});

The accumulator starts as reduce's empty-object second argument, and each pass creates or reuses a department array. The common mistake: forgetting to return groups at the end of the callback, leaving the accumulator undefined on the next pass.

Drill 6: join two arrays by a shared id​

The classic interview shape: two arrays that share an id field, combined. Add a customerName field to each order by matching customerId against the customers list.

const orders = [
{ id: 101, customerId: 1, total: 42 },
{ id: 102, customerId: 2, total: 15 },
{ id: 103, customerId: 1, total: 30 },
];

const customers = [
{ id: 1, name: 'Priya' },
{ id: 2, name: 'Sam' },
];

// add a customerName field to each order

What you should see: three orders, each now carrying a customerName of 'Priya' or 'Sam'.

Solution
const customersById = new Map(customers.map((c) => [c.id, c.name]));

const ordersWithNames = orders.map((order) => ({
...order,
customerName: customersById.get(order.customerId) ?? 'Unknown customer',
}));

Building a Map from customers first makes each lookup constant-time, instead of calling customers.find(...) inside .map(), which re-scans customers for every order. Naming that tradeoff is what interviewers listen for. The ...order spread matters too: writing order.customerName = ... directly would mutate the original array, and ?? stops a missing id from silently writing undefined.

Common mistakes​

  • Calling sort, reverse, or splice on data you still need. All three mutate in place. Spread into a copy first.
  • Forgetting the initial value in reduce. Without it, the first item becomes the accumulator, breaking once you reduce into an object.
  • Assuming flat() goes all the way down. Default depth is 1; pass Infinity for unknown nesting.
  • Using .find() inside a .map() for a join. Works, but it's O(n * m). Build a Map keyed by id once either array grows.
  • Reading a property off .find()'s result unchecked. No match returns undefined, and .someProperty throws.

Where to practice next on Scrimba​

Array methods sit under the Frontend Developer Path: React's list rendering and search filtering both depend on being comfortable with map, filter, and reduce first.

CourseWhat it drillsAccessLength
Learn JavaScriptArrays in the Blackjack game, push, pop, unshift and shift drills in Practice Time 2, arrays saved to localStorage in the Chrome extension. 140+ challenges, all free; Pro gates three Solo ProjectsFree9.4 hrs
JavaScript Interview ChallengesChef Mario's Recipe Book is Drill 2 three ways, ending in [...new Set(arr)]; Pumpkin's Prizes is Drill 3 with flat() and by hand; the Working with Data section (23 scrims) covers filter then map, reduce on a cart, and sort with a comparator. Two sample scrims free, all 28 challenges ProPro2.3 hrs
Advanced JavaScriptMethods & Loops (101 min, 22 scrims): forEach, map, filter and reduce, each with a challenge, and a .map() vs .forEach() scrim where a working map is swapped for forEach and breaks. Five sample scrims free, the rest ProPro9.8 hrs
Data Structures and AlgorithmsBig O first (a free 17-minute sample), then Maps: a nested loop finding duplicate IDs becomes one Map pass, the fix for Drill 6. Eleven challenges with Vitest test files, ten of them ProPro2.5 hrs

Drill arrays inside scrims

Learn JavaScript is free; Pro unlocks the interview challenges and paths.

Try Scrimba free (opens in a new tab)