I am trying to nest a recursive function in an Array.reduce call.
But the following does not work for the third instance only
const i1 = {'local': [['a','b']]};
const i2 = {'local': [['c','d']], 'recursive': []};
const i3 = {'local': [['c','d']], 'recursive': [{'local': [['e','f']]}]};
function reduce(current, result = []) {
if(current.hasOwnProperty('local'))
result.push(...current.local);
if(current.hasOwnProperty('recursive'))
result = current.recursive.reduce(reduce, result);
//'result =' should be optional, but yields a wrong answer anyway
return result;
}
console.log(reduce(i1));
console.log(reduce(i2));
console.log(reduce(i3));
So instead of calling reduce I tried the following loop
for(var i = 0; i < current.recursive.length; ++i)
result = reduce(current.recursive[i], result);
//'result = ' is optional for it is passed by reference
and it works.
Being new to JavaScript, I am certain of missing a key feature here, so could you explain ?
Output for the third instance should be
[ [ 'c', 'd' ], [ 'e', 'f' ] ]
but is
{ local: [ [ 'e', 'f' ] ] }
or
[ [ 'c', 'd' ] ]
when result = is removed.
The problem is the order of the parameters, the first argument to the reduce callback function is the accumulator not the current value. Try this:
const i1 = {'local': [['a','b']]};
const i2 = {'local': [['c','d']], 'recursive': []};
const i3 = {'local': [['c','d']], 'recursive': [{'local': [['e','f']]}]};
function reduce(result, current) {
if(current.hasOwnProperty('local'))
result.push(...current.local);
if(current.hasOwnProperty('recursive'))
result = current.recursive.reduce(reduce, result);
//'result =' should be optional, but yields a wrong answer anyway
return result;
}
console.log(reduce([], i1));
console.log(reduce([], i2));
console.log(reduce([], i3));
This only covers the cases when local and recursive only includes one element, like in your example.
const i1 = { local: [["a", "b"]] };
const i2 = { local: [["c", "d"]], recursive: [] };
const i3 = { local: [["c", "d"]], recursive: [{ local: [["e", "f"]] }] };
const i4 = {
local: [["c", "d"]],
recursive: [{ local: [["e", "f"]], recursive: [{ local: [["g", "h"]] }] }]
};
const solution = ({ local: [firstItem], recursive }) =>
[firstItem].concat(
recursive && recursive.length ? solution(recursive[0]) : []
);
console.log(solution(i1));
console.log(solution(i2));
console.log(solution(i3));
console.log(solution(i4));
I think what you want to implement is flatten - It's no coincidence that it's a simple wrapper for Array.prototype.flatMap -
const i1 =
{ local: [[1,2]] }
const i2 =
{ local: [[3,4]], recursive: [] }
const i3 =
{ local: [[3,4]], recursive: [{ local: [[5,6]] }] }
const i4 =
{ local: [[1,2]],
recursive: [
{ local: [[3,4]] },
{ local: [[5,6]] , recursive: [{ local: [[7,8]] }] }] }
const flatten = ({ local = [], recursive = [] }) =>
[ ...local, ...recursive.flatMap(flatten) ]
console.log(flatten(i1))
// [ [ 1, 2 ] ]
console.log(flatten(i2))
// [ [ 3, 4 ] ]
console.log(flatten(i3))
// [ [ 3, 4 ], [ 5, 6 ] ]
console.log(flatten(i4))
// [ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ], [ 7, 8 ] ]
The spread arguments can be traded for Array.prototype.concat, if that is preferred -
const flatten = ({ local = [], recursive = [] }) =>
[ ...local, ...recursive.flatMap(flatten) ]
local.concat(recursive.flatMap(flatten))
Array.prototype.flatMap is a special kind of Array.prototype.reduce -
const flatten = ({ local = [], recursive = [] }) =>
local.concat(
recursive.reduce((r, x) => r.concat(flatten(x)), [])
)
And since Array.prototype.concat is a pure operation, we can simplify it a bit more -
const flatten = ({ local = [], recursive = [] }) =>
recursive.reduce((r, x) => r.concat(flatten(x)), local)
And finally we see it again using reduce and array spread arguments -
const flatten = ({ local = [], recursive = [] }) =>
recursive.reduce((r, x) => [...r, ...flatten(x)], local)
Each of these flatten produce the exact same outputs and the input arrays are not mutated in the process. Hopefully this gives you a little insight on how the helpful Array.prototype.flatMap works.
I am facing a problem.
var arr = ['VBH', 'KTL', 'PVC', 'IF & AF', 'BC', 'CC&HC', 'UBS', 'FAD&DVD'];
var obj = [
{"materialTypeID":9,"name":"","abbreviation":"UBS","count":1,"duns":0,"plantId":0},
{"materialTypeID":18,"name":null,"abbreviation":"PVC","count":1,"duns":0,"plantId":0},
{"materialTypeID":7,"name":"","abbreviation":"FAD&DVD","count":4,"duns":0,"plantId":0}
];
and I want the result in sorting format as arr variable shows such as VBH object or KTL object if they found.
[
{"materialTypeID":18,"name":null,"abbreviation":"PVC","count":1,"duns":0,"plantId":0},
{"materialTypeID":9,"name":"","abbreviation":"UBS","count":1,"duns":0,"plantId":0},
{"materialTypeID":7,"name":"","abbreviation":"FAD&DVD","count":4,"duns":0,"plantId":0}
]
In java script, I want to implement.
Thanks,
Loop the arr and use filter to get the element from the obj. filter will return a new array, check if the length of this new array is more than 0 , then use push to put the element
var arr = ['VBH', 'KTL', 'PVC', 'IF & AF', 'BC', 'CC&HC', 'UBS', 'FAD&DVD']
var obj = [{
"materialTypeID": 9,
"name": "",
"abbreviation": "UBS",
"count": 1,
"duns": 0,
"plantId": 0
}, {
"materialTypeID": 18,
"name": null,
"abbreviation": "PVC",
"count": 1,
"duns": 0,
"plantId": 0
}, {
"materialTypeID": 7,
"name": "",
"abbreviation": "FAD&DVD",
"count": 4,
"duns": 0,
"plantId": 0
}]
let sortedArray = [];
arr.forEach(function(item) {
let getElem = obj.filter(function(items) {
return items.abbreviation === item
})
if (getElem.length > 0) {
sortedArray.push(getElem[0])
}
})
console.log(sortedArray)
It seems that you want to sort by decreasing materialTypeID.
Your problem has already been resolved there : Javascript object list sorting by object property
obj.sort(function(a, b) {
return b.materialTypeID - a.materialTypeID;
})
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}]]
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']
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.
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];
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);
Using ES6 Spread Operator
Array.prototype.concat(...searchData)
OR
[].concat(...searchData)
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]
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; }
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
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]
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' }
// }
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": []
}
]
}
]
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]
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]
// 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'