Coding Practice / Module 11 · Polyfills / Problems 101–110

Module 11: Implement Your Own Array Methods (Polyfills)

Module 6 used map, filter and reduce as black boxes. This module opens them up: build each one from scratch with a plain loop, the same way the JavaScript engine actually implements them internally. Writing a polyfill is also one of the most common "prove you understand this" interview questions there is.

Module 11 of 12 Problems 101–110 JS + Python ~45–60 Min

By the end of this module, you'll be able to

  • Reimplement map/filter/reduce/forEach/find from a plain loop, matching the real callback signature (element, index, array)
  • Explain why Python's list has no .map() method the way a JS array does
  • Recognize the loop pattern hiding underneath every one of these built-ins

1. Problems 101–110

Same format as the previous modules: expand a problem to see the approach and both commented solutions.

Why the Python side looks a little unusual here

Python's built-in map()/filter() are standalone functions, not list methods — there's no Array.prototype equivalent to patch. So each Python solution below is a standalone function that mimics what the JS method does, matching its callback signature (item, index, list) for a fair side-by-side comparison, rather than trying to bolt a new method onto Python's list type.

P101

Implement Your Own map()

[1,2,3] doubled → [2,4,6], written from scratch.

Approach: loop through the array once, call the callback with (element, index, array) on each iteration — matching the real .map()'s signature — and collect every return value into a new array.

JavaScript
my-map.js
// A minimal reimplementation of Array.prototype.map -- loop once, call the
// callback with (element, index, array), and collect the results.
function myMap(arr, callback) {
  const result = [];
  for (let i = 0; i < arr.length; i++) {
    result.push(callback(arr[i], i, arr));
  }
  return result;
}

console.log(myMap([1, 2, 3], (n) => n * 2)); // [2, 4, 6]
Python
my_map.py
def my_map(items: list, callback) -> list:
    """Python's list has no .map() method at all -- map() is a standalone built-in
    function, so this mirrors what that built-in already does under the hood."""
    result = []
    for index, item in enumerate(items):
        result.append(callback(item, index, items))
    return result

print(my_map([1, 2, 3], lambda n, i, arr: n * 2))  # [2, 4, 6]
P102

Implement Your Own filter()

[1,2,3,4] where n is even → [2, 4].

Approach: same loop shape as myMap, but only push the original element (not the callback's return value) into the result, and only when the callback returns something truthy.

JavaScript
my-filter.js
function myFilter(arr, predicate) {
  const result = [];
  for (let i = 0; i < arr.length; i++) {
    if (predicate(arr[i], i, arr)) result.push(arr[i]);
  }
  return result;
}

console.log(myFilter([1, 2, 3, 4], (n) => n % 2 === 0)); // [2, 4]
Python
my_filter.py
def my_filter(items: list, predicate) -> list:
    result = []
    for index, item in enumerate(items):
        if predicate(item, index, items):
            result.append(item)
    return result

print(my_filter([1, 2, 3, 4], lambda n, i, arr: n % 2 == 0))  # [2, 4]
P103

Implement Your Own reduce()

[1,2,3,4] summed with a starting value of 0 → 10.

Approach: the trickiest of the three: if no initial value is supplied, the real .reduce() uses the array's first element as the starting accumulator and begins looping from the second element instead of the first.

JavaScript
my-reduce.js
// If no initial value is given, the first element becomes the starting
// accumulator and the loop begins from the second element instead.
function myReduce(arr, callback, initialValue) {
  let accumulator = initialValue;
  let startIndex = 0;
  if (accumulator === undefined) {
    accumulator = arr[0];
    startIndex = 1;
  }
  for (let i = startIndex; i < arr.length; i++) {
    accumulator = callback(accumulator, arr[i], i, arr);
  }
  return accumulator;
}

console.log(myReduce([1, 2, 3, 4], (acc, n) => acc + n, 0)); // 10
Python
my_reduce.py
def my_reduce(items: list, callback, initial=None):
    if initial is None:
        accumulator = items[0]
        start_index = 1
    else:
        accumulator = initial
        start_index = 0
    for index in range(start_index, len(items)):
        accumulator = callback(accumulator, items[index], index, items)
    return accumulator

print(my_reduce([1, 2, 3, 4], lambda acc, n, i, arr: acc + n, 0))  # 10
P104

Implement Your Own forEach()

Print each item with its index — no array built or returned.

Approach: the simplest of the group — loop and call the callback, but never collect or return anything. Its entire purpose is the side effect the callback performs.

JavaScript
my-for-each.js
function myForEach(arr, callback) {
  for (let i = 0; i < arr.length; i++) {
    callback(arr[i], i, arr); // no return value collected -- purely a side effect
  }
}

myForEach(["a", "b", "c"], (item, i) => console.log(i, item));
// 0 a
// 1 b
// 2 c
Python
my_for_each.py
def my_for_each(items: list, callback) -> None:
    for index, item in enumerate(items):
        callback(item, index, items)  # no return value collected -- purely a side effect

my_for_each(["a", "b", "c"], lambda item, i, arr: print(i, item))
# 0 a
# 1 b
# 2 c
P105

Implement Your Own find()

The first number over 4 in [1,5,8,3] is 5.

Approach: loop and return the element itself the moment the predicate matches — stop scanning immediately rather than checking the rest of the array.

JavaScript
my-find.js
function myFind(arr, predicate) {
  for (let i = 0; i < arr.length; i++) {
    if (predicate(arr[i], i, arr)) return arr[i]; // return immediately -- don't keep scanning
  }
  return undefined;
}

console.log(myFind([1, 5, 8, 3], (n) => n > 4)); // 5
Python
my_find.py
def my_find(items: list, predicate):
    for index, item in enumerate(items):
        if predicate(item, index, items):  # return immediately -- don't keep scanning
            return item
    return None

print(my_find([1, 5, 8, 3], lambda n, i, arr: n > 4))  # 5
P106

Implement Your Own some() and every()

Both short-circuit — they don't always scan the whole array.

Approach: mySome returns true the instant one match is found (one success proves it); myEvery returns false the instant one mismatch is found (one failure disproves it) — both are early exits, not full scans.

JavaScript
my-some-every.js
function mySome(arr, predicate) {
  for (let i = 0; i < arr.length; i++) {
    if (predicate(arr[i], i, arr)) return true; // one match is enough
  }
  return false;
}

function myEvery(arr, predicate) {
  for (let i = 0; i < arr.length; i++) {
    if (!predicate(arr[i], i, arr)) return false; // one failure is enough to disprove it
  }
  return true;
}

console.log(mySome([1, 2, 3], (n) => n > 2));  // true
console.log(myEvery([1, 2, 3], (n) => n > 0)); // true
Python
my_some_every.py
def my_some(items: list, predicate) -> bool:
    for index, item in enumerate(items):
        if predicate(item, index, items):  # one match is enough
            return True
    return False

def my_every(items: list, predicate) -> bool:
    for index, item in enumerate(items):
        if not predicate(item, index, items):  # one failure is enough to disprove it
            return False
    return True

print(my_some([1, 2, 3], lambda n, i, arr: n > 2))   # True
print(my_every([1, 2, 3], lambda n, i, arr: n > 0))  # True
P107

Implement Your Own includes() and indexOf()

Does [1,2,3] contain 2? At which index?

Approach: both are Module 5's linear search wearing a different hat — includes just needs a yes/no answer, indexOf needs the position, and neither takes a custom callback the way the others in this module do.

JavaScript
my-includes-indexof.js
function myIncludes(arr, target) {
  for (const item of arr) {
    if (item === target) return true;
  }
  return false;
}

function myIndexOf(arr, target) {
  for (let i = 0; i < arr.length; i++) {
    if (arr[i] === target) return i;
  }
  return -1;
}

console.log(myIncludes([1, 2, 3], 2)); // true
console.log(myIndexOf([1, 2, 3], 2));  // 1
Python
my_includes_index_of.py
def my_includes(items: list, target) -> bool:
    for item in items:
        if item == target:
            return True
    return False

def my_index_of(items: list, target) -> int:
    for i in range(len(items)):
        if items[i] == target:
            return i
    return -1

print(my_includes([1, 2, 3], 2))  # True
print(my_index_of([1, 2, 3], 2))  # 1
P108

Implement Your Own flat() (One Level Deep)

[1, [2, 3], 4, [5]] → [1, 2, 3, 4, 5].

Approach: for each element, check whether it's itself a list. A plain element gets appended directly; a nested list gets its contents spread/extended in instead of being nested as a single item.

JavaScript
my-flat.js
// Concatenate each element into the result -- but if an element is itself an
// array, spread its contents in instead of nesting the whole array.
function myFlat(arr) {
  const result = [];
  for (const item of arr) {
    if (Array.isArray(item)) {
      result.push(...item); // spread one level of nesting out
    } else {
      result.push(item);
    }
  }
  return result;
}

console.log(myFlat([1, [2, 3], 4, [5]])); // [1, 2, 3, 4, 5]
Python
my_flat.py
def my_flat(items: list) -> list:
    result = []
    for item in items:
        if isinstance(item, list):
            result.extend(item)  # spread one level of nesting out
        else:
            result.append(item)
    return result

print(my_flat([1, [2, 3], 4, [5]]))  # [1, 2, 3, 4, 5]
P109

Implement Your Own sort() (With a Comparator)

Accept a comparator function, the same way the real .sort() does.

Approach: Module 8's insertion sort, generalized to accept any comparator function instead of hardcoding > — the comparator's return value (negative/zero/positive) decides the order, exactly like the real .sort().

JavaScript
my-sort.js
// A minimal sort that accepts a comparator function, the same way the real
// .sort() does -- built on Module 8's insertion sort.
function mySort(arr, compareFn) {
  const result = [...arr];
  for (let i = 1; i < result.length; i++) {
    const current = result[i];
    let j = i - 1;
    while (j >= 0 && compareFn(result[j], current) > 0) {
      result[j + 1] = result[j];
      j--;
    }
    result[j + 1] = current;
  }
  return result;
}

console.log(mySort([5, 2, 9, 1], (a, b) => a - b)); // [1, 2, 5, 9]
Python
my_sort.py
def my_sort(items: list, compare_fn) -> list:
    """compare_fn should behave like a JS comparator: negative if a comes first,
    positive if b comes first, zero if they're equal."""
    result = items[:]
    for i in range(1, len(result)):
        current = result[i]
        j = i - 1
        while j >= 0 and compare_fn(result[j], current) > 0:
            result[j + 1] = result[j]
            j -= 1
        result[j + 1] = current
    return result

print(my_sort([5, 2, 9, 1], lambda a, b: a - b))  # [1, 2, 5, 9]
P110

Run a Function N Times

Collect fn(0), fn(1), ... fn(n-1) into a list.

Approach: a small utility, not a real Array method — but it's the basis for test helpers and generative loops: loop n times, calling fn with the current iteration index each time, and collect what it returns.

JavaScript
times.js
// A small utility that's the basis for timesRepeat-style test helpers and
// animation frame loops: call fn with the current iteration index, N times.
function times(n, fn) {
  const results = [];
  for (let i = 0; i < n; i++) {
    results.push(fn(i));
  }
  return results;
}

console.log(times(5, (i) => i * i)); // [0, 1, 4, 9, 16]
Python
times.py
def times(n: int, fn) -> list:
    results = []
    for i in range(n):
        results.append(fn(i))
    return results

print(times(5, lambda i: i * i))  # [0, 1, 4, 9, 16]

2. Key Takeaways

  • Every method in this module reduces to the same shape: loop once, call a callback with (element, index, array), and decide what to do with the result — collect it (map), test it (filter/some/every), fold it (reduce), or ignore it (forEach).
  • find/some/indexOf all exit early the moment they have their answer — writing the polyfill makes that early return visible, where the built-in hides it.
  • Python's built-in map()/filter() already exist as standalone functions (not list methods) — this module's Python side shows what they do internally, not something Python is missing.