https://bfe.dev is like a LeetCode for FrontEnd developers. I’m using it to practice my skills.
This article is about the coding problem BFE.dev#3. implement Array.prototype.flat()
Goal
We are asked to implement flat() to remove the nested square brackets.
const arr = [1, [2], [3, [4]]];
flat(arr)
// [1, 2, 3, [4]]
flat(arr, 1)
// [1, 2, 3, [4]]
flat(arr, 2)
// [1, 2, 3, 4]
Recursion
The recursion approach is easy, collect result while iterating through the array.
- if meets another array, 
flat()it first, and then collect the results - if meets non-array element, just collect it in order.
 
With this in mind, following recursion approach becomes natural.
function flat(arr, depth = 1) {
  const result = []
  for (let item of arr) {
    if (Array.isArray(item) && depth > 0) {
      result.push(...flat(item, depth - 1))
    } else {
      result.push(item)
    }
  }
  return result
}
Rewrite with reduce
Seems like a good chance to use reduce. Let's modify a little.
function flat(arr, depth = 1) {
  return arr.reduce((result, item) => {
    if (Array.isArray(item) && depth > 0) {
      result.push(...flat(item, depth - 1))
    } else {
      result.push(item)
    }
    return result
  }, [])
}
Iterative Approach
When preparing for an tech interview, rewriting recursion with iteration is a must-to-know.
Let's first write down how would we remove the brackets manually. Left is the target array, right is the result array.
[1, [2], [3, [4]]]  => []
Meets 1, not array, just collect it
[[2], [3, [4]]] => [1]
next is [2] this is array, so remove the brackets, and put it back.
[2, [3, [4]]] => [1]
next is 2, so collect it
[[3, [4]]] => [1,2]
Following above steps, we can get
[3, [4]] => [1,2]
[[4]] => [1,2,3]
[4] => [1,2,3]
[] => [1,2,3,4]
One problem is the depth, we cannot just remove all the brackets, so all the element should track its own depth.
let's redo above process with depth this time.
Suppose depth is 1:
[[1, 1], [[2], 1], [[3, [4]], 1]] => []
next element is 1 with depth 1, so collect it.
[[[2], 1], [[3, [4]], 1]] => [1]
next element is [2] with depth1, so remove the brackets and push back 2 with depth 0
[[2, 0], [[3, [4]], 1]] => [1]
next is 2 with depth 0, collect it
[[[3, [4]], 1]] => [1, 2]
next is [3,[4]] with depth 1, push them back with depth 0
[[3,0],[[4],0]] => [1, 2]
collect 3
[[[4],0]] => [1, 2, 3]
now we get [4] with depth 0, since 0 we cannot remove the brackets any more, just collect [4]
[] => [1,2,3,[4]]
With above process in mind, an iterative approach is easy to come up with.
function flat(arr, depth = 1) {
  const result = []
  const stack = [...arr.map(item => ([item, depth]))]
  while (stack.length > 0) {
    const [head, depth] = stack.shift()
    if (Array.isArray(head) && depth > 0) {
      stack.unshift(...head.map(item => ([item, depth - 1])))
    } else {
      result.push(head)
    }
  }
  return result
}
There is performance concern in above approach - shift/unshift should be avoided, because every shift/unshift actually changes all rest element's indices.
To improve this, we could solve it from right to left, meaning using pop/push, and we only need to reverse it for once.
function flat(arr, depth = 1) {
  const result = []
  const stack = [...arr.map(item => ([item, depth]))]
  while (stack.length > 0) {
    const [top, depth] = stack.pop()
    if (Array.isArray(top) && depth > 0) {
      stack.push(...top.map(item => ([item, depth - 1])))
    } else {
      result.push(top)
    }
  }
  return result.reverse()
}
Ok, passed!
Hope it helps. If you are interested, give it a try on https://BFE.dev
See you next time.
              
    
Top comments (0)