JavaScript flattening an array of arrays of objects
Asked Answered
B

15

59

I have an array which contains several arrays, each containing several objects, similar to this.

[[object1, object2],[object1],[object1,object2,object3]]

Here is a screenhot of the object logged to the console.

What would be the best approach to flattening this out so it just an array of objects?

I've tried this with no luck:

console.log(searchData);  
  var m = [].concat.apply([],searchData);    
console.log(m);

searchData logs out the screenshot above, but m logs out [ ]

Here is the actual contents of searchData:

[[{"_id":"55064111d06b96d974937a6f","title":"Generic Title","shortname":"generic-title","contents":"<p>The Healing Center offers practical, social, and spiritual support to individuals and families. Services include, but are not limited to: food and clothing, job skills training and job search assistance, auto repair (Saturdays only), mentoring, financial counseling, tutoring, prayer, life skills training, and helpful information about local community services.</p><p>Stay in touch with us:</p>","__v":0},{"_id":"5508e1405c621d4aad2d2969","title":"test english","shortname":"test-page","contents":"<h2>English Test</h2>","__v":0}],[{"_id":"550b336f33a326aaee84f883","shortname":"ok-url","title":"now english","contents":"<p>okokko</p>","category":"Transportation","__v":0}]]
Buitenzorg answered 20/3, 2015 at 3:7 Comment(7)
i like arr.reduce(function(a,b){return a.concat(b);});Indecorum
for some reason that gives me an empty [ ]. Several other methods I've tried also have...I'm not sure why?Buitenzorg
you're doing something else wrong if all the options presented are not working.Indecorum
can you just post the content of searchData as well ?Thesda
Works: jsfiddle.net/m415vttvDiegodiehard
Possible duplicate of Merge/flatten an array of arrays in JavaScript?Parthenopaeus
To flatten deeply nested array of objects you need recursion. Check this post for a solution.Ruppert
T
89

You can use Array.concat like bellow:-

var arr = [['object1', 'object2'],['object1'],['object1','object2','object3']];
var flattened = [].concat.apply([],arr);

flattened will be your expected array.

ES 2020 gives the flat, also flatMap if you want to iterate over, to flat lists of lists:

[['object1'], ['object2']].flat() // ['object1', 'object2']
Thesda answered 20/3, 2015 at 3:13 Comment(7)
For some reason this returns an empty array. Any ideas why that might be occuring?Buitenzorg
i like this better even than my reduce answer.Indecorum
It works on the array provided in the answer. For some reason my array returns [ ] though.Buitenzorg
@Buitenzorg can you post what exactly you are trying?Thesda
@Thesda can you please add explanation to your code?Milinda
@NishanthMatha the trick is that .apply() takes the arguments as an array see: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…Said
Neither approach works for me. I use json_files.map((json_file: File) => { json_file.text().then(value => a_nested_array.push(JSON.parse(value))) }); to create the array and wanted to do a_nested_array.flat() ... but the nested arrays are not flattenedSprinkling
D
18

A recursive solution for deep (nested) flattening:

function flatten(a) {
  return Array.isArray(a) ? [].concat.apply([], a.map(flatten)) : a;
}

A bit more compactly with ES6:

var flatten = a => Array.isArray(a) ? [].concat(...a.map(flatten)) : a;

For fun, using a generator named F for "flatten", to lazily generate flattened values:

function *F(a) {
  if (Array.isArray(a)) for (var e of a) yield *F(e); else yield a;
}

>> console.log(Array.from(F([1, [2], 3])));
<< [ 1, 2, 3 ]

For those not familiar with generators the yield * syntax yields values from another generator. Array.from takes an iterator (such as results from invoking the generator function) and turns it into an array.

Dinka answered 20/3, 2015 at 3:25 Comment(0)
S
12

If you only need simple flatten, this may works:

var arr = [['object1', 'object2'],['object1'],['object1','object2','object3']];
var flatenned = arr.reduce(function(a,b){ return a.concat(b) }, []);

For more complex flattening, Lodash has the flatten function, which maybe what you need: https://lodash.com/docs#flatten

//Syntax: _.flatten(array, [isDeep])

_.flatten([1, [2, 3, [4]]]);
// → [1, 2, 3, [4]];

// using `isDeep` to recursive flatten
_.flatten([1, [2, 3, [4]]], true);
// → [1, 2, 3, 4];
Syblesybley answered 20/3, 2015 at 3:14 Comment(2)
good example for showing why to prefer [].reduce vs _.flatten !Indecorum
@Indecorum Well, all he needs to do is specify the optional argument to _.flatten to get the deep behavior, or call _.flattenDeep.Dinka
R
7

you can use flat() :

const data = [ [{id:1}, {id:2}], [{id:3}] ];
const result = data.flat();
console.log(result);

// you can specify the depth

const data2 = [ [ [ {id:1} ], {id:2}], [{id:3}] ];
const result2 = data2.flat(2);

console.log(result2);

in your case :

const data = [[{"_id":"55064111d06b96d974937a6f","title":"Generic Title","shortname":"generic-title","contents":"<p>The Healing Center offers practical, social, and spiritual support to individuals and families. Services include, but are not limited to: food and clothing, job skills training and job search assistance, auto repair (Saturdays only), mentoring, financial counseling, tutoring, prayer, life skills training, and helpful information about local community services.</p><p>Stay in touch with us:</p>","__v":0},{"_id":"5508e1405c621d4aad2d2969","title":"test english","shortname":"test-page","contents":"<h2>English Test</h2>","__v":0}],[{"_id":"550b336f33a326aaee84f883","shortname":"ok-url","title":"now english","contents":"<p>okokko</p>","category":"Transportation","__v":0}]]

const result = data.flat();

console.log(result);
Rapt answered 4/2, 2019 at 20:45 Comment(0)
L
5

Using ES6 Spread Operator

Array.prototype.concat(...searchData)

OR

[].concat(...searchData)

Loutitia answered 25/4, 2018 at 11:17 Comment(0)
Y
3

You can use this custom recursive method to flattened any nested array

const arr = [
  [1, 2],
  [3, 4, 5],
  [6, [7, 8], 9],
  [10, 11, 12]
]

const flatenedArray = arr => {
  let result = [];
  if(!arr.constructor === Array) return;
  arr.forEach(a => {
    if(a.constructor === Array) return result.push(...flatenedArray(a));
    result.push(a);
  });
  return result;
}


console.log(flatenedArray(arr)); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
You answered 17/2, 2022 at 16:43 Comment(0)
C
2

Recursively flatten an array:

function flatten(array) {
   return !Array.isArray(array) ? array : [].concat.apply([], array.map(flatten));
}
 
var yourFlattenedArray = flatten([[{"_id":"55064111d06b96d974937a6f","title":"Generic Title","shortname":"generic-title","contents":"<p>The Healing Center offers practical, social, and spiritual support to individuals and families. Services include, but are not limited to: food and clothing, job skills training and job search assistance, auto repair (Saturdays only), mentoring, financial counseling, tutoring, prayer, life skills training, and helpful information about local community services.</p><p>Stay in touch with us:</p>","__v":0},{"_id":"5508e1405c621d4aad2d2969","title":"test english","shortname":"test-page","contents":"<h2>English Test</h2>","__v":0}],[{"_id":"550b336f33a326aaee84f883","shortname":"ok-url","title":"now english","contents":"<p>okokko</p>","category":"Transportation","__v":0}]]
);

log(yourFlattenedArray);

function log(data) {
  document.write('<pre>' + JSON.stringify(data, null, 2) + '</pre><hr>');
}
* {font-size: 12px; }
Cetinje answered 20/3, 2015 at 3:18 Comment(13)
That worked! thank you, I'll have to dissect the code. So why is this one working when the others did not?Buitenzorg
Something vaguely non-DRY about checking for array-ness twice.Dinka
@byrdr: The other answers work fine unless you misrepresented the data.Diegodiehard
Oddly enough, I was wrong, When I replaced the array with the variable containing my array I returned [ ] againBuitenzorg
@Buitenzorg I'm using your own data. I don't understand.Cetinje
@byrdr: You have several solutions that have been verified as working, yet you report the same problem. This should tell you that the problem is elsewhere. Is this data coming from an XHR request? If so, are you not waiting for the response before logging the data?Diegodiehard
@torazaburo Good eyesCetinje
@LyeFish it is odd, they do all work on the string of json, just not on the variable. The data is coming from a promise...Buitenzorg
@Buitenzorg is the JSON parsed? JSON.parse(data) ?Cetinje
@Moogs SyntaxError: Unexpected token , Maybe that's the reason for the odd behaviorBuitenzorg
@LyeFish the variable searchData is the response data of an angular promiseBuitenzorg
@Moogs JSON.stringify returns [[],[]] ...any ideas?Buitenzorg
@byrdr: It's not worth guessing when you could just provide actual code that you're running and with the logging you're doing.Diegodiehard
A
2
let functional = {
    flatten (array) {
        if (Array.isArray(array)) {
            return Array.prototype.concat(...array.map(this.flatten, this));
        }

        return array;
    }
};

functional.flatten([0, [1, 2], [[3, [4]]]]); // 0, 1, 2, 3, 4
Anallise answered 1/8, 2015 at 23:38 Comment(1)
This answer is ECMAScript 2015 which is not covered by the javascript tag, unless the appropriate tag has been appended to the tag list of this question, a traditional JavaScript answer is expected.Hiles
M
2

I've noticed that people are using recursions which are not cost friendly, especially with new ES6 standards giving us the power of spread operators. When you're pushing the items into the master array just use ... and it will automatically add flattened objects. Something like

array.push(...subarray1)    // subarray1 = [object1, object2]
array.push(...subarray2)    // subarray2 = [object3]
array.push(...subarray3)    // subarray3 = [object4,object5, object6]
// output -> array = [object1, object2, object3, object4, object5, object6]
Mazur answered 8/1, 2019 at 7:57 Comment(0)
H
2

My solution to flatten an array of objects and return a single array.

flattenArrayOfObject = (arr) => {
  const flattened = {};

  arr.forEach((obj) => {
    Object.keys(obj).forEach((key) => {
      flattened[key] = obj[key];
    });
  });

  return flattened;
};

Example

const arr = [
  {
    verify: { '0': 'xyzNot verified', '1': 'xyzVerified' },
    role_id: { '1': 'xyzMember', '2': 'xyzAdmin' },
    two_factor_authentication: { '0': 'No', '1': 'Yes' }
  },
  { status: { '0': 'xyzInactive', '1': 'Active', '2': 'xyzSuspend' } }
]

flattenArrayOfObject(arr)

// {
//   verify: { '0': 'xyzNot verified', '1': 'xyzVerified' },
//   status: { '0': 'xyzInactive', '1': 'Active', '2': 'xyzSuspend' },
//   role_id: { '1': 'xyzMember', '2': 'xyzAdmin' },
//   two_factor_authentication: { '0': 'No', '1': 'Yes' }
// }
Harim answered 4/3, 2021 at 13:3 Comment(0)
S
1

If each object has an array and continues in the same way nested :

function flatten(i,arrayField){
  if(Array.isArray(i)) return i.map(c=>flatten(c,arrayField));
  if(i.hasOwnProperty(arrayField)) return [{...i,[arrayField]:null},...i[arrayField].map(c=>flatten(c,arrayField))];
  return {...i,[arrayField]:null};
}

let data=flatten(myData,'childs');

mydata like this :

[
{
    "id": 1,
    "title": "t1",
    "sort_order": 200,
    "childs": [
        {
            "id": 2,
            "title": "t2",
            "sort_order": 200,
            "childs": []
        },
        {
            "id": 3,
            "title":"mytitle",
            "sort_order": 200,
            "childs": []
        },
        {
            "id": 4,
            "title":"mytitle",
            "sort_order": 200,
            "childs": []
        },
        {
            "id": 5,
            "title":"mytitle",
            "sort_order": 200,
            "childs": []
        },
        {
            "id": 6,
            "title":"mytitle",
            "sort_order": 200,
            "childs": []
        }
    ]
},
{
    "id": 7,
    "title": "راهنما",
    "sort_order":"mytitle",
    "childs": [
        {
            "id": 8,
            "title":"mytitle",
            "sort_order": 200,
            "childs": []
        },
        {
            "id": 9,
            "title":"mytitle",
            "sort_order": 200,
            "childs": []
        },
        {
            "id": 10,
            "title":"mytitle",
            "sort_order": 200,
            "childs": []
        }
    ]
}

]

Soapstone answered 17/6, 2021 at 14:44 Comment(0)
B
1

JavaScript flat is a way to achieve a flattened array from a multidimensional array

For two dimentional array

const data = [
  [{id: 1, name: 'Test Name'}], 
  [{id: 2, name: 'Test Name 2'}]
 ].flat()
console.log(data)

For multidimensional array

const data = [
  [{id: 1, name: 'Test Name'}], 
  [
    {id: 2, name: 'Test Name 2'}, 
    [{id: 3, name: 'Test Name 3'}]
  ]
].flat(Infinity)
console.log(data)
Blumenfeld answered 11/12, 2023 at 6:56 Comment(0)
O
0

let nestedArray = [[1, 2], [3, 4], [5, 6]];

let flattenArray = function(nestedArray) {

	let flattenArr = [];
  
	nestedArray.forEach(function(item) {
  	flattenArr.push(...item);
  });
  
  return flattenArr;
};

console.log(flattenArray(nestedArray)); // [1, 2, 3, 4, 5, 6]
Orgulous answered 6/10, 2018 at 16:9 Comment(0)
N
0
var arr = [1,[9,22],[[3]]];
var res = [];

function flatten(arr){
for(let i=0;i<arr.length;i++){
if(typeof arr[i] == "number"){
res.push(arr[i]);
}
else if(typeof arr[i] == "object"){
fatten(arr[i]);
}
}
}

Calling function

flatten(arr);
console.log(res);

Result  

[1, 9, 22, 3]
Nihil answered 13/11, 2018 at 10:28 Comment(0)
I
0

// Polyfill flat method

var flatten = a => Array.isArray(a) ? [].concat(...a.map(flatten)) : a;

var deepFlatten = (arr, depth = 1) => {
   return depth > 0 ? arr.reduce((acc, val) => acc.concat(Array.isArray(val) ? deepFlatten(val, depth - 1) : val), [])
                : arr.slice();
}

console.log(deepFlatten([0, 1, 2, [[[3, 4]]]], Infinity));

// You can pass label in place of 'Infinity'
Incurrent answered 10/12, 2021 at 8:57 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.