How to make recursively nested array in javascript? - javascript

Below is the json I have:
{
"name": "test",
"characteristics": [
{
"name": "A",
"description": "",
"comprisedOf": [
{
"name": "A1",
"description": "",
"comprisedOf": [
{
"name": "A1.1",
"description": "",
"value": "10"
},
{
"name": "A1.2",
"description": "",
"value": "5"
}
]
},
{
"name": "A2",
"description": "",
"value": "100"
},
{
"name": "A3",
"description": "",
"value": "20"
},
{
"name": "A4",
"description": "",
"value": "50"
}
]
},
{
"name": "B",
"description": "",
"value": "10"
}
]
}
Here I have 2 characteristics object of "test" - A and B.These 2 objects may or may not have "comprisedOf" array. For Eg A has"comprisedOf" array whereas B has not. These comprisedOf array further may or may not have comprisedof objects array.
Now i have to make an array out of this which should be like the given below array:-
[
{
"name": "test",
"children": [
{
"name": "A",
"children": [
{
"name":"A1",
"children:: [
{
"name": "A1.1"
},
{
"name": "A1.2"
}
]
},
{
"name": "A2"
},
{
"name": "A3"
},
{
"name": "A4"
}
]
},
{
"name": "B"
}
]
}
]
How this array can be formed recursively out of the first array?
Thanks so much!!
EDIT:- Here's what I have tried:-
var makeChildrenAll = function(dataChar){
dataChar.forEach(function(char){
if(char.comprisedOf) {
makeChildrenAll(char.comprisedOf);
}
childrenData.push({
name: char.name,
description: char.description,
children: childrenData
});
});
};
makeChildrenAll(dataChar);

In order to be recursive you want the function to return and be able to assign that return to current object
Something like
function mapItems(arr){
// return new array
return arr.reduce((a,c)=>{
var newObj={name:c.name};
if(Array.isArray(c.comprisedOf)){
// use returned array of recursive function to assign to `children` property
newObj.children = mapItems(c.comprisedOf)
}
return a.concat(newObj)
},[])
}
console.log(mapItems(data.characteristics))
.as-console-wrapper { max-height: 100%!important;}
<script>
var data ={
"name": "test",
"characteristics": [
{
"name": "A",
"description": "",
"comprisedOf": [
{
"name": "A1",
"description": "",
"comprisedOf": [
{
"name": "A1.1",
"description": "",
"value": "10"
},
{
"name": "A1.2",
"description": "",
"value": "5"
}
]
},
{
"name": "A2",
"description": "",
"value": "100"
},
{
"name": "A3",
"description": "",
"value": "20"
},
{
"name": "A4",
"description": "",
"value": "50"
}
]
},
{
"name": "B",
"description": "",
"value": "10"
}
]
}
</script>

You could take a different start array and use a destructuring for the wanted properties.
function mapItems(array) {
return array.map(({ name, comprisedOf }) =>
Object.assign({ name }, comprisedOf && { children: mapItems(comprisedOf) }));
}
var data = { name: "test", characteristics: [{ name: "A", description: "", comprisedOf: [{ name: "A1", description: "", comprisedOf: [{ name: "A1.1", description: "", value: "10" }, { name: "A1.2", description: "", value: "5" }] }, { name: "A2", description: "", value: "100" }, { name: "A3", description: "", value: "20" }, { name: "A4", description: "", value: "50" }] }, { name: "B", description: "", value: "10" }] };
console.log(mapItems([{ name: data.name, comprisedOf: data.characteristics }]));
.as-console-wrapper { max-height: 100% !important; top: 0; }
ES5
function mapItems(array) {
return array.map(function (o) {
var r = { name: o.name };
if (o.comprisedOf) {
r.children = mapItems(o.comprisedOf);
}
return r;
});
}
var data = { name: "test", characteristics: [{ name: "A", description: "", comprisedOf: [{ name: "A1", description: "", comprisedOf: [{ name: "A1.1", description: "", value: "10" }, { name: "A1.2", description: "", value: "5" }] }, { name: "A2", description: "", value: "100" }, { name: "A3", description: "", value: "20" }, { name: "A4", description: "", value: "50" }] }, { name: "B", description: "", value: "10" }] };
console.log(mapItems([{ name: data.name, comprisedOf: data.characteristics }]));
.as-console-wrapper { max-height: 100% !important; top: 0; }

Related

Loop through JSON in dataLayer

I would like to get the summed value of all the arrays in the "products" object (price * quantity). The summed value should be returned in the return.
Do you have any ideas how to do that?
{
"event": "checkout",
"ecommerce": {
"checkout": {
"actionField": {
"step": 2,
"option": "Initiate checkout",
"action": "checkout"
},
"products": [
{
"id": "52",
"name": "Turystyczna kuchenka gazowa SMILE-KN-03/1K",
"price": 161.788618,
"brand": "",
"category": "kuchenki-elektryczne-i-gazowe",
"variant": "",
"quantity": "1"
},
{
"id": "36",
"name": "Kuchnia gazowa MPM-51-KGF-21",
"price": 641.463415,
"brand": "",
"category": "kuchnie-gazowe",
"variant": "",
"quantity": "1"
}
]
}
},
"gtm.uniqueEventId": 12
}
const g = {
event: 'checkout',
ecommerce: {
checkout: {
actionField: {
step: 2,
option: 'Initiate checkout',
action: 'checkout',
},
products: [
{
id: '52',
name: 'Turystyczna kuchenka gazowa SMILE-KN-03/1K',
price: 161.788618,
brand: '',
category: 'kuchenki-elektryczne-i-gazowe',
variant: '',
quantity: '1',
},
{
id: '36',
name: 'Kuchnia gazowa MPM-51-KGF-21',
price: 641.463415,
brand: '',
category: 'kuchnie-gazowe',
variant: '',
quantity: '1',
},
],
},
},
'gtm.uniqueEventId': 12,
};
const c = g.ecommerce.checkout.products.reduce((acc, curr) => {
acc += curr.price * curr.quantity;
return acc;
}, 0);
console.log(c)
guess you want something like this?

Creating an object which contains unique item from a nested array

I have an array of objects called employees. I need a solution that will return me a list of groups and respective employees present in the group along with the group properties.
The example is below, I have used an object but the result can also be an array that has a property called groupName within an object. [{groupName:"developer", employees:[],...}..] As long as the response returns a list of groups with their corresponding employees.
Below is the solution I did but I need a solution with a better time complexity that is O(n).
const employees = [
{ "name": "John Doe",
"id": "1",
"groups": [
{ "id": "developerId", "name": "developer", "color": "#fff" },
{ "id": "engineerId", "name": "engineer", "color": "#fff" }
],
"groupId":["developerId", "engineerId"]
},
{ "name": "Jane Doe",
"id": "2",
"groups": [
{ "id": "developerId", "name": "developer", "color": "#fff" },
{ "id": "testerId", "name": "tester", "color": "#fff" }
],
"groupId":["developerId", "testerId"]
}
]
//Solution O(m*n)
let groups = {};
employees.forEach((item) => {
item.groups.forEach((group) => {
if (!groups[group.name]) {
groups[group.name] = {
employees: [item.id],
...group,
};
} else {
groups[group.name].employees = [...groups[group.name].employees, item.id];
}
});
});
//result
{
"developer":{
"id":"developerId",
"employee":[
"1",
"2"
],
"color":"#fff"
},
"engineer":{
"id":"employeeId",
"employee":[
"1",
],
"color":"#fff"
},
"tester":{
"id":"testerId",
"employee":[
"2",
],
"color":"#fff"
}
}
Using Array#reduce and Array#forEach:
const employees = [
{
"name": "John Doe",
"id": "1",
"groups": [
{ "id": "developerId", "name": "developer", "color": "#fff" },
{ "id": "engineerId", "name": "engineer", "color": "#fff" }
],
"groupId": ["developerId", "engineerId"]
},
{
"name": "Jane Doe",
"id": "2",
"groups": [
{ "id": "developerId", "name": "developer", "color": "#fff" },
{ "id": "testerId", "name": "tester", "color": "#fff" }
],
"groupId": ["developerId", "testerId"]
}
];
const groups = employees.reduce((acc, { id: employeeId, groups = [] }) => {
groups.forEach(({ id, name, color }) => {
acc[name] = {
id, color, employee: [...(acc[name]?.employee ?? []), employeeId]
};
});
return acc;
}, {});
console.log(groups);
If you like to add some speed, you could use the old fashioned for statement for iterating, especially of having only a single result object.
This approach does not create an object again and again and uses the already existing objects.
const
employees = [{ name: "John Doe", id: "1", groups: [{ id: "developerId", name: "developer", color: "#fff" }, { id: "engineerId", name: "engineer", color: "#fff" }], groupId: ["developerId", "engineerId"] }, { name: "Jane Doe", id: "2", groups: [{ id: "developerId", name: "developer", color: "#fff" }, { id: "testerId", name: "tester", color: "#fff" }], groupId: ["developerId", "testerId"] }],
result = {};
for (const { id: employeeId, groups } of employees) {
for (const { id, name, color } of groups) {
result[name] ??= { id, color, employee: [] };
result[name].employee.push(employeeId);
}
}
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

How to order an array of objects in array of categories in javascript?

I have the following array of objects
{
"nome": "jose",
"categoria": [
{ "id": "1" },
{ "id": "3" },
]
},
{
"nome": "maria",
"categoria": [
{ "id": "2" },
]
},
{
"nome": "pedro",
"categoria": [
{ "id": "1" },
]
}
I have to reorder in another array of categories. Something like this:
{
"id": "1",
"pessoas": [
{
"nome": "jose",
"categoria": [
{ "id": "1" },
{ "id": "3" },
]
},
{
"nome": "pedro",
"categoria": [
{ "id": "1" },
]
},
]
},
{
"id": "2",
"pessoas": [
{
"nome": "maria",
"categoria": [
{ "id": "2" }
]
},
]
},
I have try with the function reduce(), but I couldn't because it is not an object, but a array of objects (categoria)
const group = data.reduce((r, array) => {
r[array.categoria.id] = [...r[array.categoria.id] || [], array];
return r;
}, {});
Someone can help me please?
You could take an object for grouping by id. Inside of reduce, categoria is iterated as well for getting the needed id.
var data = [{ nome: "jose", categoria: [{ id: "1" }, { id: "3" }] }, { nome: "maria", categoria: [{ id: "2" }] }, { nome: "pedro", categoria: [{ id: "1" }] }],
result = Object.values(data.reduce((r, o) => {
o.categoria.forEach(({ id }) => {
if (!r[id]) r[id] = { id, pessoas: [] };
r[id].pessoas.push(o);
});
return r;
}, {}));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Creating a new array from the parents of array child element

I have the following array
{
"id": "111",
"name": "1111",
"children": [
{
"id": "22222",
"name": "2222",
"children": [
{
"id": "AAAA",
"name": "AAAA",
"children": [
{
"id": "DDD",
"name": "DDD"
},
{
"id": "EEE",
"name": "EEE"
}
]
},
{
"id": "BBBB",
"name": "BBB",
"children": [
{
"id": "FFF",
"name": "FFF"
},
{
"id": "GGG",
"name": "GGG",
"children": [
{
"id": "7777",
"name": "7777"
},
{
"id": "8888",
"name": "8888"
}
]
}
]
}
]
}
]
}
And I would like to create an array with the parents of a child by its ID.
So for example if I wanted to get the path to the child with ID "FFF", then the array would look like something like this:
["1111", "2222", "BBB", "FFF"]
How could I go about doing that?
You could take an iterative and recursive approach.
function getItems({ children, ...object }, key, value) {
var temp;
if (object[key] === value) return [object];
if (children) children.some(o => temp = getItems(o, key, value));
return temp && [object, ...temp];
}
var data = { id: "111", name: "1111", children: [{ id: "22222", name: "2222", children: [{ id: "AAAA", name: "AAAA", children: [{ id: "DDD", name: "DDD" }, { id: "EEE", name: "EEE" }] }, { id: "BBBB", name: "BBB", children: [{ id: "FFF", name: "FFF" }, { id: "GGG", name: "GGG", children: [{ id: "7777", name: "7777" }, { id: "8888", name: "8888" }] }] }] }] };
console.log(getItems(data, 'id', 'FFF'));
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could implement a recursive search to find all paths and return the correct one when you reach the desired name-value pair.
const isObject = (obj) => obj === Object(obj);
let data = loadData();
let expected = [ '1111', '2222', 'BBB', 'FFF' ];
let actual = findPath(data, 'name', 'FFF');
console.log(JSON.stringify(expected) === JSON.stringify(actual));
function findPath(data, key, value, includeIndicies=false) {
let opts = { found : null, includeIndicies : includeIndicies };
findPathInternal(data, key, value, opts, []);
return opts.found;
}
function findPathInternal(node, key, val, opts, path) {
if (Array.isArray(node)) {
for (let i = 0; i < node.length; i++) {
findPathInternal(node[i], key, val, opts, opts.includeIndicies ? path.concat(i) : path);
}
} else if (isObject(node)) {
if (node[key] === val) {
opts.found = path.concat(val); return; // Exit
} else {
let keys = Object.keys(node);
for (let i = 0; i < keys.length; i++) {
findPathInternal(node[keys[i]], key, val, opts, path.concat(node[key]));
}
}
}
};
function loadData() {
return {
"id": "111",
"name": "1111",
"children": [{
"id": "22222",
"name": "2222",
"children": [{
"id": "AAAA",
"name": "AAAA",
"children": [{
"id": "DDD",
"name": "DDD"
},
{
"id": "EEE",
"name": "EEE"
}
]
},
{
"id": "BBBB",
"name": "BBB",
"children": [{
"id": "FFF",
"name": "FFF"
},
{
"id": "GGG",
"name": "GGG",
"children": [{
"id": "7777",
"name": "7777"
},
{
"id": "8888",
"name": "8888"
}
]
}
]
}
]
}]
};
}
.as-console-wrapper { top: 0; max-height: 100% !important; }

Javascript Loop and filter out the data thats null or empty

I have some data and I need to filter out the data thats null or empty and create a new data list thats filtered.
In this case sometimes "names" array is null so I need that data out.
{
"people": [
{
"id": "2",
"description": "desc here",
"names": [
{
"name": "name here",
},
{
"name": "name here",
}
],
"other": "0"
},
{
"id": "200",
"description": "desc here",
"names": null
"other": "0"
},
{
"id": "64",
"description": "desc here",
"names": [
{
"name": "name here",
},
{
"name": "name here",
}
],
"other": "1"
}
]
}
How can I do this?
You could iterate the arrays and objects recursive until a primitive is found. Then check and return the value.
function copy(object) {
var o;
if (Array.isArray(object)) {
return object.reduce(function (r, a) {
var v = copy(a);
v.names !== null && v.names !== '' && r.push(v);
return r;
}, []);
}
if (object !== null && typeof object === 'object') {
o = {};
Object.keys(object).forEach(function (k) {
o[k] = copy(object[k]);
});
return o;
}
return object;
}
var data = { people: [{ id: "2", description: "desc here", names: [{ id: "345", name: "name here", }, { id: "54", name: "name here", foo: "", }], other: "0" }, { id: "2", description: "desc here", names: null, other: "0" }, { id: "64", description: "desc here", names: [{ id: "87", name: "name here", }, { id: "53", name: "name here", }], other: "1" }] },
result = copy(data);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
var newArray = oldArray.filter(function(v){return v!==''});
new_array=yourObject.people.filter(function(elem){
return elem.names!==null && elem.names!==""
});

Categories

Resources