11

I have a horrible looking array which looks like this:

EDIT:

array = [
    {
        Letters: [{ Letter: 'A' }, { Letter: 'B' }, { Letter: 'C' }],
        Numbers: [{ Number: '1' }, { Number: '2' }, { Number: '3' }]
    },
    null,
    {
        Letters: [{ Letter: 'D' }, { Letter: 'E' }, { Letter: 'F' }, { Letter: 'G' }, { Letter: 'H' }],
        Numbers: [{ Number: '4' }, { Number: '5' }, { Number: '6' }, { Number: '7' }]
    }
];

And want the array to look like this:

flattenedArray = [a,b,c,1,2,3,d,e,f,g,h,4,5,6,7]

Unfortunately I cannot change the original formatting because that is the form received when merging two API responses that I am getting.

I have tried using:

var flattenedArray = [].concat.apply([], array);

But it just presents the array in the same format it was entered in.

I was wondering if anybody had any advice?

EDIT: I have tried implementing the suggestions given - thank you so much for your help. It seems it is a problem with the format of the list - unfortunately using the chrome console which is in a 'tree' format I cannot see the direct structure of the array output.

Thank you for all your help! EDIT 2: See above for the actual array, thank you for showing me how to see this!

7
  • 1
    That's not exactly valid JS array syntax. Was this just a misrepresentation in your question, or is it actually a string you are receiving that looks exactly like this?
    – Bergi
    Commented Dec 26, 2016 at 13:09
  • I'm not sure what the string exactly looks like, it is how I interpretted it looking from the developer tools on chrome. I can't figure out how to stop it presenting the information as a tree but it looks more like:
    – Jess
    Commented Dec 26, 2016 at 13:24
  • 1
    Then please show us (edit it into your question) the output that console.log(JSON.stringify(array)) generates. Getting a tree view suggests that you are not having a plain string
    – Bergi
    Commented Dec 26, 2016 at 13:29
  • 2
    Oh well, that's actually not just a nested array but a nested array of objects. Which invalidates all the answers :-(
    – Bergi
    Commented Dec 26, 2016 at 13:49
  • 1
    @jess, now you have to treat the objects as well as the arrays. What do you want with null? Commented Dec 26, 2016 at 14:55

10 Answers 10

9

Edit for the new request of nested arrays/objects and the flattening, you could use a combined approach with testing for the type of an element.

var array = [{ Letters: [{ Letter: 'A' }, { Letter: 'B' }, { Letter: 'C' }], Numbers: [{ Number: '1' }, { Number: '2' }, { Number: '3' }] }, null, { Letters: [{ Letter: 'D' }, { Letter: 'E' }, { Letter: 'F' }, { Letter: 'G' }, { Letter: 'H' }], Numbers: [{ Number: '4' }, { Number: '5' }, { Number: '6' }, { Number: '7' }] }],
    result = array.reduce(function iter(r, a) {
        if (a === null) {
            return r;
        }
        if (Array.isArray(a)) {
            return a.reduce(iter, r);
        }
        if (typeof a === 'object') {
            return Object.keys(a).map(k => a[k]).reduce(iter, r);
        }
        return r.concat(a);
    }, []);

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Old request and the immortal question how to flat a nested array.

var flat = (r, a) => Array.isArray(a) ? a.reduce(flat, r) : r.concat(a),
    inputArray = array = [[['a', 'b', 'c'], [1, 2, 3]], [], [['d', 'e', 'f', 'g', 'h'], [4, 5, 6, 7]]],
    outputArray = inputArray.reduce(flat, []);

console.log(outputArray);

1
  • 2
    Just tested it out and it works a charm - thank you for taking the time to help!
    – Jess
    Commented Dec 26, 2016 at 14:59
9

If you have lodash, you can use:

_.flattenDeep(array)

You can also checkout their source code for ides on how to implement yourself if you prefer.

8

You can create recursive function using forEach() that will return new array.

var array = [[['a','b','c'],[1,2,3]],[],[['d','e','f','g','h'],[4,5,6,7]]]
function flat(data) {
  var r = []
  data.forEach(e => Array.isArray(e) ? r = r.concat(flat(e)) : r.push(e));
  return r;
}

console.log(flat(array))

You can also use reduce() instead of forEach()

var array = [[['a','b','c'],[1,2,3]],[],[['d','e','f','g','h'],[4,5,6,7]]]

function flat(data) {
  return data.reduce((r, e) => Array.isArray(e) ? r = r.concat(flat(e)) : r.push(e) && r, [])
}

console.log(flat(array))

As @Bergi suggested you can use reduce() like this.

data.reduce((r, e) => r.concat(Array.isArray(e) ? flat(e) : [e]), [])
5
  • && r will kill readability. I'm sure many people will not understand purpose of it. I'd suggest splitting code into 2 lines and using return r instead
    – Rajesh
    Commented Dec 26, 2016 at 11:59
  • s/can/should/ use reduce. If you want imperative iteration, use a for…of loop instead of forEach with an arrow function.
    – Bergi
    Commented Dec 26, 2016 at 13:10
  • 1
    Btw, in the case of concat you don't need to reassign r. Better just use (r, e) => r.concat(Array.isArray(e) ? flat(e) : [e]) as the reducer.
    – Bergi
    Commented Dec 26, 2016 at 13:11
  • @Bergi Wow that is great, just why brackets on : [e] how about data.reduce((r, e) => r.concat(Array.isArray(e) ? flat(e) : e), [])? Commented Dec 26, 2016 at 13:28
  • Because only arrays should be passed to concat. Plain values kinda work as well, but concat always has to check whether they are spreadable like arrays (which since ES6 is also not exactly the same any more)
    – Bergi
    Commented Dec 26, 2016 at 13:31
2

It's nice to use a recursive function for such cases:

arr = [[['a','b','c'],[1,2,3]],[],[['d','e','f','g','h'],[4,5,6,7]]];

function flatten(arr) {
    var result = [];
    for (var i = 0, len = arr.length; i < len; i++) {
       result = result.concat(Array.isArray(arr[i])? flatten(arr[i]) : [arr[i]]);
    }
    return result;
}
console.log(flatten(arr));

2

You could try the flatten function in Ramda.

  R.flatten([1, 2, [3, 4], 5, [6, [7, 8, [9, [10, 11], 12]]]]);
    //=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
1
  • 😂,, you are obsessed by ramda . Commented Feb 20, 2017 at 3:22
1

Your Array format is not correct, you are missing commas(,). This is correct array.

var array = [[['a','b','c'],[1,2,3]],[],[['d','e','f','g','h'],[4,5,6,7]]];

var array = [[['a','b','c'],[1,2,3]],[],[['d','e','f','g','h'],[4,5,6,7]]];
var result = flatten(array);
    
function flatten(array) {
    var flat = [];
    if(array !== undefined){
    var flat = [];
    for (var i = 0; i < arguments.length; i++) {
          if (arguments[i] instanceof Array) {
            flat = flat.concat(flatten.apply(null, arguments[i]));
          } else {
            flat.push(arguments[i]);
          }
        }
      }
    return flat;
}

console.log(result);

1
  • I believe this code flattens just one level deep; for deeper flattening, you would need to run this recursively. Or use lodash, as I suggested ;)
    – Luan Nico
    Commented Dec 26, 2016 at 11:49
1

No one thought of splicing in-place?

function flatten(array){
    for (var i = 0; i < array.length; i++) {
        if(array[i] instanceof Array){
            array.splice.apply(array,[i,1].concat(array[i]));
            i--;
        }
    };
    return array;
}

One iteration, no recursion.

1

Implement flatten function using recursion and spread operator.

const a = [1,[2,[3,4],[5]],6];
const flatten = (arr) => {
    const res = []
    for(let i=0;i<arr.length;i++) {
        if(!Array.isArray(arr[i])) res.push(arr[i]);
        else res.push(...flatten(arr[i]));
    }
    return res;
}
console.log(flatten(a));

0
function steamrollArray(arr) {
  var tmp = [];
  arr.forEach(function(val){
    if(Array.isArray(val))
      tmp = tmp.concat(steamrollArray(val));
    else
      tmp.push(val);
  });

  console.log(tmp);
  return tmp;
}

steamrollArray([1, [2], [3, [[4]]]]);
0
let arr = [1,2,[3,4]]

/* let newarr = arr.flat(); */

let newarr = Object.values(arr);
let arr2 = []
for(let val of Object.values(arr)) {
         if(!Array.isArray(val)){
     console.log(val)
     arr2.push(val)
     }    
           for ( let val2 of Object.values(val)){
             arr2.push(val2)
           }
}
console.log(arr2)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.