80

The following code

function steamrollArray(arr) {
  // I'm a steamroller, baby
  return arr.flat();
}

steamrollArray([1, [2], [3, [[4]]]]);

returns

arr.flat is not a function

I tried it in Firefox and Chrome v67 and the same result has happened.

What's wrong?

zero298
  • 25,467
  • 10
  • 75
  • 100
TechnoKnight
  • 961
  • 1
  • 6
  • 9
  • 2
    Its [experimental](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat). What browser are you on? – Phix Jun 22 '18 at 18:09
  • 1
    What browser? Did you look at the [availability table](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat)? – zero298 Jun 22 '18 at 18:09
  • Yes, I have seen it and I tried it in Firefox, when it didn't work, I tried again with Chrome(which is supported, last version) and the same result has happened. – TechnoKnight Jun 22 '18 at 18:11
  • What version of Chrome are you using? – chuckx Jun 22 '18 at 18:11
  • 1
    @TechnoKnight Chrome **69+** is supported. Which version of Chrome do you have? –  Jun 22 '18 at 18:12
  • Oops, I have 67 version lol. – TechnoKnight Jun 22 '18 at 18:14
  • May I ask something, what about freecodecamp console, is it linked to browser or not? – TechnoKnight Jun 22 '18 at 18:14
  • chrome 69 is not even released as a stable – baao Jun 22 '18 at 18:15
  • It’s also available in Firefox Nightly only, as, again, the documentation on MDN states. – Sebastian Simon Jun 22 '18 at 18:17
  • Oh man! That means that I will have to write the code manually, sigh. Well, thank you a lot though! – TechnoKnight Jun 22 '18 at 18:20
  • @TechnoKnight Details, details. :) As an alternative, you can either implement the method yourself, or use one from a library such as Lodash: https://lodash.com/docs/4.17.10#flattenDeep –  Jun 22 '18 at 18:20
  • I will just build the method myself. Thank you all for helping me! And sorry for misleading you by saying that I have the latest version of Chrome, well, I thought that I had the latest version(it seems that 69 is not stable, just beta) – TechnoKnight Jun 22 '18 at 18:21

11 Answers11

78

The flat method is not yet implemented in common browsers (only Chrome v69, Firefox Nightly and Opera 56). It’s an experimental feature. Therefore you cannot use it yet.

You may want to have your own flat function instead:

Object.defineProperty(Array.prototype, 'flat', {
    value: function(depth = 1) {
      return this.reduce(function (flat, toFlatten) {
        return flat.concat((Array.isArray(toFlatten) && (depth>1)) ? toFlatten.flat(depth-1) : toFlatten);
      }, []);
    }
});

console.log(
  [1, [2], [3, [[4]]]].flat(2)
);

The code was taken from here by Noah Freitas originally implemented to flatten the array with no depth specified.

Ivan
  • 34,531
  • 8
  • 55
  • 100
  • 2
    That would be equivalent to `arr.flat(Infinity)`, but not with the default argument of `1` – Patrick Roberts Jun 22 '18 at 18:16
  • 2
    @Ivan [`flat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat) takes one argument that defines the flattening depth. This polyfill doesn’t. – Sebastian Simon Jun 22 '18 at 18:21
  • Just run your code snippet to test it. Your 4 is still in an array. – Matt Jun 22 '18 at 18:31
  • @Matt It should be ([result is `[1,2,3,[4]]` on Chrome v69](https://i.stack.imgur.com/KSal5.png)). – Ivan Jun 22 '18 at 20:35
  • 1
    you may want to not use depth-1 as your condition, if you pass in 0, that becomes -1 which is equal to true, and not false. – WORMSS Apr 03 '19 at 07:07
  • @WORMSS, thank you for noticing the error, I corrected it by replacing the condition with `depth > 1`. – Ivan Apr 03 '19 at 07:31
  • 1
    @RotimiBest That's weird. I checked and it works on Chrome v74. Can you try typing `Array.prototype.flat` in your console? – Ivan May 10 '19 at 11:13
  • At the end of 2019 `flat()` is no longer experimental and is supported in all modern browsers (so everywhere except IE and Edge … and it will come to Edge when it switches to the Blink rendering engine in the near future). – Quentin Nov 13 '19 at 13:19
  • 1
    september 2020, still an issue :/ – Ambroise Rabier Sep 12 '20 at 09:36
35

This can also work.

let arr = [ [1,2,3], [2,3,4] ];
console.log([].concat(...arr))

Or for older browsers,

[].concat.apply([], arr);
dubucha
  • 1,027
  • 10
  • 16
16

Array.flat is not supported by your browser. Below are two ways to implement it.

As a function, the depth variable specifies how deep the input array structure should be flattened (defaults to 1; use Infinity to go as deep as it gets) while the stack is the flattened array, passed by reference on recursive calls and eventually returned.

function flat(input, depth = 1, stack = [])
{
    for (let item of input)
    {
        if (item instanceof Array && depth > 0)
        {
            flat(item, depth - 1, stack);
        }
        else {
            stack.push(item);
        }
    }
    
    return stack;
}

As a Polyfill, extending Array.prototype if you prefer the arr.flat() syntax:

if (!Array.prototype.flat)
{
    Object.defineProperty(Array.prototype, 'flat',
    {
        value: function(depth = 1, stack = [])
        {
            for (let item of this)
            {
                if (item instanceof Array && depth > 0)
                {
                    item.flat(depth - 1, stack);
                }
                else {
                    stack.push(item);
                }
            }
            
            return stack;
        }
    });
}
resu
  • 944
  • 12
  • 21
  • no idea why flat doesn't work in my node v12, anyway thx for flat func, copy and get what i need <3 – Yegor Mar 08 '20 at 18:45
5

Similar issue, solved by using ES6 .reduce() method:

const flatArr = result.reduce((acc, curr) => acc.concat(curr),[]);
irina
  • 1,261
  • 1
  • 9
  • 10
2

use _.flatten from lodash package ;)

Bash Lord
  • 127
  • 1
  • 10
1
var arr=[[1,2],[3,4],[5,6]];
var result=[].concat(...arr);
console.log(result);    //output: [ 1, 2, 3, 4, 5, 6 ]
AntiRakPro
  • 11
  • 1
  • While this code snippet may solve the problem, it doesn't explain why or how it answers the question. Please [include an explanation for your code](//meta.stackexchange.com/q/114762/269535), as that really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. – Luca Kiebel Jan 18 '22 at 10:52
0

Another simple solution is _.flattenDeep() on lodash

https://lodash.com/docs/4.17.15#flattenDepth

const flatArrays = _.flattenDeep([1, [2], [3, [[4]]]]);

console.log(flatArrays);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
Mo.
  • 26,306
  • 36
  • 159
  • 225
0
const array = [
  [
    [6, 6],
    [3, 3],
  ],
  [[7, 7, [9]]],
]

function simplifyArray(array) {
  const result = []

  function recursivePushElem(arr) {
    arr.forEach(i => {
      if (Array.isArray(i)) recursivePushElem(i)
      else result.push(i)
    })
  }
  recursivePushElem(array)

  console.log(result)
  return result
}

simplifyArray(array)
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jan 03 '22 at 21:31
0

you could simply use this [].concat(...objArrs) that would work the same as the flat() method and allow more compatibility in browsers

0

You can set your full array to a string then split it. .toString().split(',')

Updated due to community bot. So basically if you want to flatten out an array that does contain any objects but strictly strings or numbers, by using .toString() it converts each element of the array to a string (if it isn't already), and then joins all of the elements together using a comma as a separator.

Once we have our string all separated by a comma we can use .split() to create an array.

NOTE*** The reason this wont work with objects is that .toString() will return [object object] as it is the default string representation of an object in JavaScript.

If your array consists solely of numbers than you would need to map through your array and convert each string number value to a number.

const array1 = [
  ['one', 'oneTwo'],
  'two',
  'three',
  'four',
]
console.log('a1', array1.toString().split(','))

const numberArray = [1, 2, [3, 4, [5, 6]], [[7, [8,9]]], 10]; 
console.log(numberArray.toString().split(',').map(num => Number(num)));
  • 1
    As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jan 28 '23 at 00:00
-3

Not sure if it is a valid answer however in my attemp to flat an array I employed the destructuring_assignment introduced in ES6.

// typeScriptArray:Array<Object> = new Array<Object>();
let concatArray = [];

let firstArray = [1,2,3];
let secondArray = [2,3,4];

concatArray.push(...firstArray);
concatArray.push(...secondArray);

console.log(concatArray);

It works like a charm even though I'm not sure if any broswer compatibily issues may arise.

giannis christofakis
  • 8,201
  • 4
  • 54
  • 65