Skip to the code
cf.

Array.prototype.flat

MediumPolyfills

Write Array.prototype.myFlat(depth), which works like the built-in flat without calling it (or flatMap). It returns a new array in which every nested array is replaced by its elements, down to depth levels of nesting.

depth defaults to 1, and Infinity flattens everything. A depth of 0 or less flattens nothing, but still returns a new array.

Only real arrays (those Array.isArray accepts) are flattened: strings, array-likes, and other objects are added as they are. Holes are dropped at every level that gets flattened, including the top one. The original array never changes.

const nested = [1, [2, [3, [4]]]];
nested.myFlat();         // [1, 2, [3, [4]]]
nested.myFlat(2);        // [1, 2, 3, [4]]
nested.myFlat(Infinity); // [1, 2, 3, 4]
[1, , [2, , 3]].myFlat(); // [1, 2, 3]

What the tests check

  1. flattens one level by default
    expect([1, [2, [3]]].myFlat()).toEqual([1, 2, [3]]);
    expect([[1], [2, 3], []].myFlat()).toEqual([1, 2, 3]);
    
  2. flattens down to the given depth
    const nested = [1, [2, [3, [4]]]];
    expect(nested.myFlat(1)).toEqual([1, 2, [3, [4]]]);
    expect(nested.myFlat(2)).toEqual([1, 2, 3, [4]]);
    
  3. flattens everything with Infinity
    expect([1, [2, [3, [4, [5, [6]]]]]].myFlat(Infinity)).toEqual([1, 2, 3, 4, 5, 6]);
    
  4. returns a new, shallow copy for a depth of 0 or less
    const inner = [2];
    const array = [1, inner];
    const copy = array.myFlat(0);
    expect(copy).toEqual([1, [2]]);
    expect(copy).not.toBe(array);
    expect(copy[1]).toBe(inner);
    expect(array.myFlat(-1)).toEqual([1, [2]]);
    
  5. drops holes at every level it flattens
    const result = [1, , [2, , 3]].myFlat();
    expect(result).toEqual([1, 2, 3]);
    expect(result).toHaveLength(3);
    
  6. only flattens real arrays
    const arrayLike = { length: 1, 0: "x" };
    const result = [["a"], "bc", arrayLike].myFlat();
    expect(result).toEqual(["a", "bc", arrayLike]);
    expect(result[2]).toBe(arrayLike);
    
  7. doesn't change the original array
    const nested = [1, [2, [3]]];
    nested.myFlat(Infinity);
    expect(nested).toEqual([1, [2, [3]]]);
    
  8. works without the built-in flat or flatMap
    const builtIns = [Array.prototype.flat, Array.prototype.flatMap];
    const forbidden = () => {
      throw new Error("myFlat called the built-in flat or flatMap");
    };
    Array.prototype.flat = forbidden;
    Array.prototype.flatMap = forbidden;
    let result;
    try {
      result = [1, [2, [3]]].myFlat(Infinity);
    } finally {
      [Array.prototype.flat, Array.prototype.flatMap] = builtIns;
    }
    expect(result).toEqual([1, 2, 3]);
    

Learn more

solution.jsSaved in this browser

Run tests runs every test on your code, here in your browser. The problem is solved when they all pass.

Ctrl + Enter runs the tests (⌘ + Enter on a Mac).