DEV Community

Cover image for Flattening Arrays in JavaScript — The Complete Visual Guide
Janmejai Singh
Janmejai Singh

Posted on

Flattening Arrays in JavaScript — The Complete Visual Guide

🪆 Flattening Arrays in JavaScript — The Complete Visual Guide

Imagine a Russian nesting doll. You open one, find another. Open that, find another. That's a nested array. Our job? Unpack them all into one flat row.


📦 What Are Nested Arrays?

A nested array is simply an array that contains other arrays as its elements. Arrays inside arrays. Boxes inside boxes.

// Simple flat array
const flat = [1, 2, 3, 4, 5];

// Nested array — arrays inside arrays
const nested = [1, [2, 3], [4, [5, 6]], [[[7]]]];
Enter fullscreen mode Exit fullscreen mode

Visualizing the layers:

[1, [2, 3], [4, [5, 6]], [[[7]]]]
 ^   ^^^^^   ^^^^^^^^^^   ^^^^^^
 |   |        |            |
 |   depth 1  depth 1+2    depth 1+2+3
 depth 0 (top level)
Enter fullscreen mode Exit fullscreen mode

These show up all the time in real code:

  • 🌐 API responses — deeply nested JSON objects
  • 🗃️ Database results — grouped or paginated data
  • 📁 File system trees — folders containing folders
  • 🧮 Matrix math — rows and columns
  • 🗺️ Category trees — parent/child hierarchies

🤔 Why Flatten at All?

Here's the problem with nested arrays:

const scores = [[85, 92], [78, 95], [88, 71]];

// ❌ .includes() won't work as expected
scores.includes(85); // false — it's looking for [85, 92]

// ❌ .length is misleading
scores.length; // 3 — but there are 6 actual scores

// ❌ Can't sort all values directly
scores.sort(); // sorts sub-arrays, not values
Enter fullscreen mode Exit fullscreen mode

After flattening:

const flat = scores.flat();
// → [85, 92, 78, 95, 88, 71]

flat.includes(85);  // ✅ true
flat.length;        // ✅ 6
flat.sort((a, b) => a - b); // ✅ [71, 78, 85, 88, 92, 95]
Enter fullscreen mode Exit fullscreen mode

🧠 The Core Concept

Flattening = pulling all values out of their nested containers into a single flat array.

BEFORE:                        AFTER:
┌──────────────────────┐       ┌────────────────────────────┐
│ [                    │       │                            │
│   1,                 │       │  [ 1, 2, 3, 4, 5, 6, 7 ]  │
│   [2, 3],            │  ──►  │                            │
│   [4, [5, 6]],       │       └────────────────────────────┘
│   [[[7]]]            │
│ ]                    │
└──────────────────────┘
Enter fullscreen mode Exit fullscreen mode

The key variable: how deep do you need to flatten?

Depth What it does
1 Unwraps only the outermost arrays
2 Unwraps two levels
Infinity Fully flattens everything

🛠️ Every Method, Explained

1️⃣ Array.flat() — The Native, Modern Way

flat() was introduced in ES2019 and is the most readable, idiomatic solution.

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

arr.flat();           // depth 1 (default)
// → [1, 2, 3, 4, [5, 6], [[[7]]]]

arr.flat(2);          // depth 2
// → [1, 2, 3, 4, 5, 6, [[[7]]]]

arr.flat(Infinity);   // flatten everything
// → [1, 2, 3, 4, 5, 6, 7]
Enter fullscreen mode Exit fullscreen mode

Step-by-step for flat(1):

Input: [1, [2, 3], [4, [5, 6]]]

1         → not an array → keep: 1
[2, 3]    → array at depth 1 → unwrap: 2, 3
[4, [5,6]]→ array at depth 1 → unwrap: 4, [5,6]
                                     ↑ still nested (depth 2)

Output: [1, 2, 3, 4, [5, 6]]
Enter fullscreen mode Exit fullscreen mode

Use when: Working in modern codebases. Clean, expressive, handles depth.


2️⃣ flatMap() — Map + Flatten in One Pass

flatMap() maps each element and then flattens one level. It's like a supercharged .map().

const words = ["Hello World", "JS is great"];

words.map(w => w.split(" "));
// → [["Hello", "World"], ["JS", "is", "great"]]

words.flatMap(w => w.split(" "));
// → ["Hello", "World", "JS", "is", "great"]
Enter fullscreen mode Exit fullscreen mode

Real-world: extract all tags from a blog array:

const posts = [
  { title: "Async Await", tags: ["js", "async"] },
  { title: "CSS Grid",    tags: ["css", "layout"] },
  { title: "Node.js",     tags: ["node", "js"] },
];

const allTags = posts.flatMap(p => p.tags);
// → ["js", "async", "css", "layout", "node", "js"]

const uniqueTags = [...new Set(allTags)];
// → ["js", "async", "css", "layout", "node"]
Enter fullscreen mode Exit fullscreen mode

Use when: You need to transform + flatten simultaneously. Only goes 1 level deep.


3️⃣ reduce() — The Foundational Approach

Before flat() landed in ES2019, reduce() was the standard approach. Still great to know.

const arr = [1, [2, 3], [4, 5]];

const flat = arr.reduce((acc, val) => acc.concat(val), []);
// → [1, 2, 3, 4, 5]
Enter fullscreen mode Exit fullscreen mode

Step-by-step accumulation:

Initial:  acc = []

Item 1:   val = 1       → [].concat(1)        = [1]
Item 2:   val = [2, 3]  → [1].concat([2,3])   = [1, 2, 3]
Item 3:   val = [4, 5]  → [1,2,3].concat([4,5]) = [1, 2, 3, 4, 5]
Enter fullscreen mode Exit fullscreen mode

For deep flattening with reduce — use recursion:

function deepFlatReduce(arr) {
  return arr.reduce((acc, val) =>
    Array.isArray(val)
      ? acc.concat(deepFlatReduce(val))
      : acc.concat(val),
  []);
}

deepFlatReduce([1, [2, [3, [4]]]]);
// → [1, 2, 3, 4]
Enter fullscreen mode Exit fullscreen mode

Use when: You want custom logic while flattening (filter, transform, accumulate).


4️⃣ Recursive Flatten — The Interview Essential

This is the approach you must be able to write from scratch in interviews.

function flatten(arr) {
  const result = [];

  for (const item of arr) {
    if (Array.isArray(item)) {
      result.push(...flatten(item)); // recurse deeper
    } else {
      result.push(item);             // base case
    }
  }

  return result;
}

flatten([1, [2, [3, [4, [5]]]]]);
// → [1, 2, 3, 4, 5]
Enter fullscreen mode Exit fullscreen mode

Call stack diagram for flatten([1, [2, [3]]]):

flatten([1, [2, [3]]])
├─ item = 1           push 1
└─ item = [2, [3]]    recurse:
      flatten([2, [3]])
      ├─ item = 2         push 2
      └─ item = [3]       recurse:
            flatten([3])
            └─ item = 3     push 3
            return [3]
      return [2, 3]
   push ...2, 3
return [1, 2, 3]
Enter fullscreen mode Exit fullscreen mode

Use when: Interviews, learning, or environments without ES2019 support.


5️⃣ Iterative Stack — Recursion-Safe 🔐

Deep recursion can cause stack overflow for extremely nested arrays. This stack-based approach avoids that:

function flattenSafe(arr) {
  const stack = [...arr];
  const result = [];

  while (stack.length) {
    const item = stack.pop();

    if (Array.isArray(item)) {
      stack.push(...item); // push elements back to process
    } else {
      result.unshift(item); // prepend to maintain order
    }
  }

  return result;
}

flattenSafe([1, [2, [3, [4, [5]]]]]);
// → [1, 2, 3, 4, 5]
Enter fullscreen mode Exit fullscreen mode

Use when: Handling user-generated or untrusted deeply nested data.


📊 Quick Comparison

Method Depth Control ES Version Best For
flat() ✅ Configurable ES2019 Most use cases
flatMap() 1 level only ES2019 Map + flatten
reduce() With recursion ES5 Custom logic
Recursion ✅ Full ES5 Interviews
Stack iterative ✅ Full ES5 Very deep nesting

🎯 Interview Questions You'll Actually Face

❓ "Write your own implementation of flat()"

Array.prototype.myFlat = function(depth = 1) {
  const result = [];

  function walk(arr, d) {
    for (const item of arr) {
      if (Array.isArray(item) && d > 0) {
        walk(item, d - 1);
      } else {
        result.push(item);
      }
    }
  }

  walk(this, depth);
  return result;
};

[1, [2, [3]]].myFlat(1);        // [1, 2, [3]]
[1, [2, [3]]].myFlat(Infinity); // [1, 2, 3]
Enter fullscreen mode Exit fullscreen mode

❓ "Flatten and remove duplicates"

const arr = [[1, 2], [2, 3], [3, [3, 4]]];

[...new Set(arr.flat(Infinity))];
// → [1, 2, 3, 4]
Enter fullscreen mode Exit fullscreen mode

❓ "Flatten only arrays, keep objects intact"

function flattenArraysOnly(arr) {
  return arr.reduce((acc, val) => {
    if (Array.isArray(val)) {
      acc.push(...flattenArraysOnly(val));
    } else {
      acc.push(val); // objects, strings, numbers — kept as-is
    }
    return acc;
  }, []);
}

flattenArraysOnly([1, [2, { a: 3 }], [[4]]]);
// → [1, 2, { a: 3 }, 4]
Enter fullscreen mode Exit fullscreen mode

❓ "Find the max nesting depth"

function maxDepth(arr) {
  return Array.isArray(arr)
    ? 1 + Math.max(0, ...arr.map(maxDepth))
    : 0;
}

maxDepth([1, [2, [3, [4]]]]);
// → 4
Enter fullscreen mode Exit fullscreen mode

❓ "Flatten and extract values from objects in an array"

const data = [
  { name: "Alice", hobbies: ["reading", "coding"] },
  { name: "Bob",   hobbies: ["gaming", "cooking"] },
];

data.flatMap(person => person.hobbies);
// → ["reading", "coding", "gaming", "cooking"]
Enter fullscreen mode Exit fullscreen mode

🧾 Cheat Sheet

const arr = [1, [2, [3, [4]]]];

// ── Native flat ──────────────────────────────
arr.flat()            // [1, 2, [3, [4]]]     (depth 1)
arr.flat(2)           // [1, 2, 3, [4]]       (depth 2)
arr.flat(Infinity)    // [1, 2, 3, 4]         (full)

// ── flatMap ──────────────────────────────────
[[1,2],[3,4]].flatMap(x => x)  // [1, 2, 3, 4]

// ── reduce ───────────────────────────────────
arr.reduce((a,v) => a.concat(v), [])
// [1, 2, [3, [4]]]  (depth 1)

// ── recursive ────────────────────────────────
function df(a) {
  return a.reduce((acc, v) =>
    acc.concat(Array.isArray(v) ? df(v) : v), []);
}
df(arr)  // [1, 2, 3, 4]
Enter fullscreen mode Exit fullscreen mode

🏆 Key Takeaways

  • 🥇 flat(Infinity) is the cleanest way to fully flatten in modern JS
  • flatMap() is perfect when you're transforming data at the same time
  • 🧠 Recursive flatten is a must-know for interviews — understand it cold
  • 🔒 Iterative/stack approach is safest for arbitrarily deep or unknown nesting
  • 🤔 Always ask yourself: "How many levels deep do I actually need?"

💻 Try It!

// Flatten, deduplicate, and sort
const challenge = [[5, 3], [1, [9, 2]], [[[8, 4]]]];

const result = [...new Set(challenge.flat(Infinity))]
  .sort((a, b) => a - b);

console.log(result);
// → [1, 2, 3, 4, 5, 8, 9]
Enter fullscreen mode Exit fullscreen mode

If this helped, drop a ❤️ and share it with a fellow dev!

Top comments (0)