Skip to content

Instantly share code, notes, and snippets.

@Integralist
Created May 20, 2015 08:35
Show Gist options
  • Save Integralist/749153aa53fea7168e7e to your computer and use it in GitHub Desktop.
Save Integralist/749153aa53fea7168e7e to your computer and use it in GitHub Desktop.
Array flatten function written in ES6 syntax
const flattenTco = ([first, ...rest], accumulator) =>
(first === undefined)
? accumulator
: (Array.isArray(first))
? flattenTco([...first, ...rest])
: flattenTco(rest, accumulator.concat(first))
const flatten = (n) => flattenTco(n, []);
console.log(flatten([[1,[2,[[3]]]],4,[5,[[[6]]]]]))
@christophemarois
Copy link

Deep version of @mnpenner

const flatten = arr => {
  while (arr.find(el => Array.isArray(el))) arr = Array.prototype.concat(...arr)
  return arr
}

@federicofazzeri
Copy link

federicofazzeri commented Sep 15, 2017

function flatten(arr) {
    return arr.reduce( (acc,arr) => [...acc, ...arr], []);
}

@gkatsanos
Copy link

@christophemarois : how performant is that? 👍

@christophemarois
Copy link

@gkatsanos not really, you are right. This is the most performant version I can think of, though it's not as succinct.

const flatten = arr => {
  let i = 0
  while (i < arr.length) {
    if (Array.isArray(arr[i])) {
      arr.splice(i, 1, ...arr[i])
    } else {
      i++
    }
  }
  return arr
}

It iterates on an array from left to right, staying on the same index as long as the current index is an array. It then uses splice to remove the array from the current index and insert its flatten elements at the current position. Because arr.length is computed at every loop iteration, it will update on each loop to match the array's current length.

@r3wt
Copy link

r3wt commented Jan 1, 2018

@christophemarois a little short

const flatten = arr => {
    let i = 0
    while (i < arr.length) {
        Array.isArray(arr[i]) && arr.splice(i, 1, ...arr[i])  || i++
    }
    return arr
}

OR

const flatten = arr => {
    for (let i=0; i < arr.length;Array.isArray(arr[i]) && arr.splice(i, 1, ...arr[i])  || i++){}
    return arr
}

you can even omit return statement, since the array is modified by reference and will be mutated

@rulyaryu
Copy link

rulyaryu commented Jan 8, 2018

@Phederic, doesn't work without Babel, and with Babel works..but not as expected
function flatten(arr) {
return arr.reduce( (acc,arr) => [...acc, ...arr], []);
}
let res = flatten([1, [2], 3, 4]); //logs [2]

@bt4R9
Copy link

bt4R9 commented Mar 5, 2018

Hi guys.
I've created a 5 test cases with different approaches. Can someone plz explain me why while+shift+concat+push technique is the fastest one?
Perhaps concat is the cheapest operation.

const flatten_loop = arr => {
  let stack = [];
  let item;
  
  while (item = arr.shift()) {
    if (Array.isArray(item)) {
      arr = item.concat(arr);
    } else {
      stack.push(item);
    }
  }
  
  return stack;
}

Test cases
https://jsperf.com/flatten-variants

@YoussefLagtab
Copy link

YoussefLagtab commented Mar 29, 2018

`/* flatten depth 1 */
let flatten = arr => [].concat(...arr);

/**

flatten depth d < 4
not working properly
*/
let flattend =(arr, d)=>{
return d===1 ? flatten(arr) : flatten(flatten(arr, d-1))
}`

@vikas199
Copy link

is there any alternative regardless flatten

@dominique-mueller
Copy link

I'm using the following, and it works like a charm:

export function flattenArray( array: Array<any> ): Array<any> {
    const flattenedArray: Array<any> = [].concat( ...array );
    return flattenedArray.some( Array.isArray )
        ? flattenArray( flattenedArray )
        : flattenedArray;
}

@laukstein
Copy link

@arilotter
Copy link

@bt4R9 your code has a bug. You can't just check if a value is truthy, you must check if it's undefined, otherwise the method stops processing. For example, flatten_loop([1,null,2]) will equal [1], not [1,null,2].

This version should fix that:

const flatten_loop = arr => {
  let stack = [];
  let item;
  
  while ((item = arr.shift()) !== undefined) {
    if (Array.isArray(item)) {
      arr = item.concat(arr);
    } else {
      stack.push(item);
    }
  }
  
  return stack;
}

@sachingvit
Copy link

var a = [1,2,3,[1,2,3],4,[5,6,7], 9,10] ;
var result = [];
a.forEach(data=>{
	result = [...result].concat(data) 
}) 

console.log(result);

Output
[1, 2, 3, 1, 2, 3, 4, 5, 6, 7, 9, 10]

@Ch1sKey
Copy link

Ch1sKey commented Mar 23, 2019

Not effective but interesting!

arr = [1,2,3,[4,5,[1,2,3,4,56,67],6,7,[7.5,7.6,7.9],8],9,10,11]

const flat = (arr, depth= Infinity ,arr2 = []) =>{
    arr.forEach(e => {
        typeof e === 'object' && depth ? flat(e, depth-1 ,arr2) : arr2.push(e)
    });
    return arr2
}

console.log(flat( arr, 1 )) // [ 1, 2, 3, 4, 5, [ 1, 2, 3, 4, 56, 67 ], 6, 7, [ 7.5, 7.6, 7.9 ], 8, 9, 10, 11 ]  // Depth 1 falt
console.log(flat(arr)) // [ 1, 2, 3, 4, 5, 1, 2, 3, 4, 56, 67, 6, 7, 7.5, 7.6, 7.9, 8, 9, 10, 11 ]  // Full flat

@moimikey
Copy link

moimikey commented Mar 31, 2019

const deepFlat = (arr) => arr.flat(Infinity)

@yzrzya1
Copy link

yzrzya1 commented Jun 9, 2019

one hack solution. (deep nested also works)
JSON.stringify(arr).split(',').map(each => each.match(/[+-]?\d+(?:\.\d+)?/g)[0])

@coolskin2b
Copy link

one hack solution. (deep nested also works)
JSON.stringify(arr).split(',').map(each => each.match(/[+-]?\d+(?:\.\d+)?/g)[0])
work like a charm for number, but not with string ['un', 2, 'trois', 4, 'cinq'].

@DimitryDushkin
Copy link

For immutable solution, this should be the most performant one, because it uses only pop() and push():

const flatten = (list) => { 
  const stack = [list];
  const result = [];

  while(stack.length > 0) {
    const elem = stack.pop();
    if (Array.isArray(elem)) {
      for (let i = elem.length - 1; i >= 0; i--) {
        stack.push(elem[i]);
      }
    } else {
      result.push(elem);
    }
  }

  return result;
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment