1

I am trying to flatten an array but I'm having difficulties.

My code:

    var arr = [["2"],["3", "4"], "5", [["6"], ["7"]] ];
    
    var res = [].concat.apply([], arr);
    
    //Using reduce(ES5)

   function test(args){
     var sum = args.reduce(function(acc, val){
       acc.concat(Array.isArray(val)? test(val): val);
     });
    }

    //Regular implementation
    function test2(arr){
      var result = [];
      arr.forEach(function(val){
        if(Array.isArray(val)){
          result = [].concat.apply([], val);
        } else {
          result.concat(val);
        }
      });
      return result;
    }
    
    console.log(test(arr));
    console.log(test2(arr));

Expected Output:

["2", "3", "4","5", "6", "7"]

Can someone enlighten me where I'm going wrong?

TechnoCorner
  • 4,151
  • 8
  • 27
  • 62
  • [Check out this link](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce) – Jhecht Feb 17 '17 at 07:12
  • @Jhecht i did try that intitally, but it was written in ES6. I have added my ES5 version but am not sure what am i doing wrong over there. It's giving me undefined. – TechnoCorner Feb 17 '17 at 07:15
  • Possible duplicate of [Merge/flatten an array of arrays in JavaScript?](http://stackoverflow.com/questions/10865025/merge-flatten-an-array-of-arrays-in-javascript) – Andreas Feb 17 '17 at 07:18
  • @Andreas Not sure if this is exact duplicate as OP is referring to nested structure. `[[[]], [[]]]` and not `[[],[],[]]` – Rajesh Feb 17 '17 at 07:28
  • @Rajesh http://stackoverflow.com/a/15030117/402037 -> `flatten([[[1, [1.1]], 2, 3], [4, 5]]); // [1, 1.1, 2, 3, 4, 5]` – Andreas Feb 17 '17 at 07:30
  • @Andreas Yes this answer is made to serve nested structure but as of question, still not sure if its a dupe and will hold my answer and vote. – Rajesh Feb 17 '17 at 07:36
  • Your `test` function is not returning anything; you need to add `return sum;` to the end of it. – Shaggy Feb 17 '17 at 07:43

4 Answers4

5

Thats it. So simple

var arr = [["2"], ["3", "4"], "5", [["6"], ["7"]]];

function test2(arr) {
    return arr.toString().split(",");
}

console.log(test2(arr));
m87
  • 4,193
  • 3
  • 13
  • 31
Sagar V
  • 11,083
  • 7
  • 41
  • 62
  • 3
    ahh, clever approach, should be the accepted answer. – m87 Feb 17 '17 at 07:25
  • 2
    Only works with arrays of strings without commas. Does not work for `[{foo: 1}, [{age: 2}, {foo: 3}]]` or `['a string, has commas']` – iblamefish Feb 17 '17 at 08:06
  • i answered for OP's question. There are different scenarios. As JavaScript runs on browser, each line of code is more important to keep efficiency. In this scenario, this line is most efficient. – Sagar V Feb 17 '17 at 08:08
4

Since its a nested structure, you should use recursion

Logic

  • Loop over passed array and check if current item is an array.
  • If yes, repeat the process.
  • If not, push value to temp array.
  • Merge return value of each recursion to previous one.

Array.forEach

var arr = [["2"],["3", "4"], "5", [["6"], ["7"]] ];

function getFlattenArray(array){
  var _tmp = [];
  array.forEach(function(item){
    if(Array.isArray(item)) {
      _tmp = _tmp.concat(getFlattenArray(item))
    }
    else{
      _tmp.push(item);
    }
  })
  return _tmp;
}

var result = getFlattenArray(arr);

console.log(result)

Array.reduce

var arr = [["2"],["3", "4"], "5", [["6"], ["7"]] ];

function getFlattenArray(array){
  return array.reduce(function(p,c){
    if(Array.isArray(c)) {
      p = p.concat(getFlattenArray(c))
    }
    else{
      p.push(c);
    }
    return p
  }, [])
}

var result = getFlattenArray(arr);

console.log(result)

ES6 Version

var arr = [["2"],["3", "4"], "5", [["6"], ["7"]] ];

function getFlattenArray(array){
  return array.reduce((p,c) => (Array.isArray(c) ? p=p.concat(getFlattenArray(c)) : p.push(c) ) && p, [])
}

var result = getFlattenArray(arr);

console.log(result)
Community
  • 1
  • 1
Rajesh
  • 21,405
  • 5
  • 35
  • 66
1

I think the reason the code I linked you wasn't working was that you probably made the same error I did. I believe (don't really care to look it up, someone will correct me if I am wrong) that arrow functions automatically return the last line, so when turning the code into ES5 you forget to return the arr.reduce(...).

This works for me, Chrome on Windows.

var arr = [
  ["2"],
  ["3", "4"], "5", [
    ["6"],
    ["7"]
  ]
];

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

console.log(flatten(arr));
Jhecht
  • 4,040
  • 1
  • 26
  • 39
1

var arr = [["2"],["3", "4"], "5", [["6"], ["7"]] ];

var flatten = arr.flat(Infinity);

console.log(flatten);

Since Array.prototype.flat() has been included in the standard ECMAScript 2019 (ES10), there is no need to implement your own methods to flatten arrays.

The flat method can take a parameter to specify how deep a nested array structure should be flattened. In the above example I'm passing the global scope variable Infinity so it flattens all the levels.

At the time of writing (04/11/2019) all major browsers except Edge have implemented the feature in their newer versions. Babel 7.4.0 (with core-js@3) also comes with it.

f-CJ
  • 3,332
  • 1
  • 26
  • 27