Lesson 02-Essential Frontend Algorithm Techniques

Array Methods as Algorithms

Let’s start with something you use every day: array methods. Did you know that map, filter, reduce, forEach, find, some, every—these are all algorithmic patterns baked into JavaScript? When you use arr.map(...), you’re applying a transformation algorithm. When you use arr.filter(...), you’re applying a filtering algorithm.

Understanding these methods as algorithms helps you compose them effectively and reason about their performance.

The map Algorithm: Transformation

Array.prototype.map() applies a function to every element in an array and returns a new array with the results. Under the hood, it’s a simple algorithm:

FOR each element in input array:
  apply callback to element
  push result to output array
RETURN output array

Time complexity: O(n) where n = array length. Space complexity: O(n) (new array).

// The map algorithm, implemented manually
function mapAlgorithm(arr, callback) {
  const result = new Array(arr.length); // Pre-allocate for performance
  for (let i = 0; i < arr.length; i++) {
    result[i] = callback(arr[i], i, arr);
  }
  return result;
}

// Usage
const numbers = [1, 2, 3, 4, 5];
const doubled = mapAlgorithm(numbers, x => x * 2);
console.log(doubled); // [2, 4, 6, 8, 10]

Why pre-allocate? In the manual implementation above, we use new Array(arr.length) instead of [] and push. This is a micro-optimization: push might trigger multiple array resizes (amortized O(1), but still some overhead). Pre-allocating ensures exactly one memory allocation.

The deeper algorithmic insight: map is a pure function—it doesn’t modify the original array, and given the same input, it always produces the same output. This makes it predictable and testable. In functional programming terms, map is a functor operation—it maps a function over a structure while preserving the structure.

The filter Algorithm: Selective Inclusion

Array.prototype.filter() creates a new array with all elements that pass a test implemented by the provided function.

FOR each element in input array:
  IF callback(element) is truthy:
    push element to output array
RETURN output array

Time complexity: O(n). Space complexity: O(k) where k = number of passing elements (worst case O(n)).

// The filter algorithm, implemented manually
function filterAlgorithm(arr, predicate) {
  const result = [];
  for (let i = 0; i < arr.length; i++) {
    if (predicate(arr[i], i, arr)) {
      result.push(arr[i]);
    }
  }
  return result;
}

// Practical example: filtering API response data
const users = [
  { id: 1, name: 'Alice', active: true },
  { id: 2, name: 'Bob', active: false },
  { id: 3, name: 'Charlie', active: true },
];

const activeUsers = filterAlgorithm(users, user => user.active);
console.log(activeUsers); // [{ id: 1, ... }, { id: 3, ... }]

Algorithmic pattern: filter is often followed by map (or vice versa). This is so common that there’s a functional programming operation called filterMap or you can just chain them: arr.filter(predicate).map(mapper). Each chaining step creates a new intermediate array—for very large arrays, this can be inefficient. An alternative is to combine the filter and map into a single loop (a fusion optimization):

// Chaining: creates intermediate array (less efficient for large n)
const result = largeArray
  .filter(x => x > 0)
  .map(x => x * 2);

// Fused: single pass, no intermediate array
const result2 = [];
for (const x of largeArray) {
  if (x > 0) result2.push(x * 2);
}

The reduce Algorithm: The Swiss Army Knife

Array.prototype.reduce() is the most general array algorithm. It accumulates array elements into a single value (which could be a number, string, object, array—anything). Almost every other array method can be implemented with reduce.

SET accumulator = initialValue (or first element if no initialValue)
FOR each element in array (starting from index 0, or 1 if no initialValue):
  accumulator = callback(accumulator, element, index, array)
RETURN accumulator

Time complexity: O(n). Space complexity: O(1) (excluding the accumulator itself).

// The reduce algorithm, implemented manually
function reduceAlgorithm(arr, callback, initialValue) {
  let accumulator = initialValue;
  let startIndex = 0;
  
  if (initialValue === undefined) {
    if (arr.length === 0) throw new TypeError('Reduce of empty array with no initial value');
    accumulator = arr[0];
    startIndex = 1;
  }
  
  for (let i = startIndex; i < arr.length; i++) {
    accumulator = callback(accumulator, arr[i], i, arr);
  }
  
  return accumulator;
}

// Powerful example: grouping objects by a key
const users = [
  { id: 1, department: 'engineering' },
  { id: 2, department: 'design' },
  { id: 3, department: 'engineering' },
  { id: 4, department: 'design' },
  { id: 5, department: 'management' },
];

const grouped = reduceAlgorithm(
  users,
  (acc, user) => {
    const dept = user.department;
    if (!acc[dept]) acc[dept] = [];
    acc[dept].push(user);
    return acc;
  },
  {} // initial value: empty object
);

console.log(grouped);
// {
//   engineering: [{ id: 1, ... }, { id: 3, ... }],
//   design: [{ id: 2, ... }, { id: 4, ... }],
//   management: [{ id: 5, ... }]
// }

The deep algorithmic insight: reduce is based on the concept of folding a data structure. In category theory, this is related to catamorphisms—a way to deconstruct a data structure by applying a combining function. If you’re curious, look up “fold” in functional programming literature.

Implementing Other Array Methods with reduce

Since reduce is so general, you can implement map, filter, find, some, every, and more using just reduce:

// map with reduce
function mapWithReduce(arr, callback) {
  return arr.reduce((acc, item, index) => {
    acc.push(callback(item, index));
    return acc;
  }, []);
}

// filter with reduce
function filterWithReduce(arr, predicate) {
  return arr.reduce((acc, item) => {
    if (predicate(item)) acc.push(item);
    return acc;
  }, []);
}

// find with reduce (returns first match)
function findWithReduce(arr, predicate) {
  return arr.reduce((found, item) => {
    if (!found && predicate(item)) return item;
    return found;
  }, undefined);
}

// some with reduce (checks if at least one element passes)
function someWithReduce(arr, predicate) {
  return arr.reduce((hasMatch, item) => {
    return hasMatch || predicate(item);
  }, false);
}

// every with reduce (checks if all elements pass)
function everyWithReduce(arr, predicate) {
  return arr.reduce((allPass, item) => {
    return allPass && predicate(item);
  }, true);
}

This demonstrates the expressive power of reduce—it’s a universal array algorithm.

More Array Methods: flat, flatMap, find, findIndex

Let’s look at a few more array methods that are useful in frontend development.

flat and flatMap: Flatten nested arrays.

// flat algorithm (simplified, without depth parameter)
function flatAlgorithm(arr) {
  return arr.reduce((acc, item) => {
    if (Array.isArray(item)) {
      acc.push(...flatAlgorithm(item)); // Recursively flatten
    } else {
      acc.push(item);
    }
    return acc;
  }, []);
}

console.log(flatAlgorithm([1, [2, [3, [4]], 5]])); // [1, 2, 3, 4, 5]

// flatMap = map + flat (single pass, more efficient)
const sentences = ['Hello world', 'How are you'];
const words = sentences.flatMap(sentence => sentence.split(' '));
console.log(words); // ['Hello', 'world', 'How', 'are', 'you']

find and findIndex: Find the first element that passes a test.

// find algorithm
function findAlgorithm(arr, predicate) {
  for (let i = 0; i < arr.length; i++) {
    if (predicate(arr[i], i, arr)) {
      return arr[i];
    }
  }
  return undefined;
}

// findIndex algorithm
function findIndexAlgorithm(arr, predicate) {
  for (let i = 0; i < arr.length; i++) {
    if (predicate(arr[i], i, arr)) {
      return i;
    }
  }
  return -1;
}

const users = [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }];
console.log(findAlgorithm(users, u => u.id === 2)); // { id: 2, name: 'Bob' }
console.log(findIndexAlgorithm(users, u => u.id === 2)); // 1

Membership Required

You must be a member to access this content.

View Membership Levels

Already a member? Log in here

Share your love