Related
i have following example array(object):
[
{
"id": 1,
"name": "selling",
"detail": [
{
"id": 11,
"name": "sale-report",
"detail": [
{ "id": 111, "name": "sale-report1", "detail": [] },
{ "id": 112, "name": "sale-report2", "detail": [] }
]
}
]
},
{
"id": 2,
"name": "webstore",
"detail": [
{
"id": 11,
"name": "sale-report",
"detail": [
{ "id": 111, "name": "webstore-report1", "detail": [] },
{ "id": 112, "name": "webstore-report2", "detail": [] }
]
}
]
},
{
"id": 2,
"name": "setting",
"detail": [
{
"id": 11,
"name": "general",
"detail": [
{ "id": 111, "name": "setting-general1", "detail": [] },
{ "id": 112, "name": "setting-general2", "detail": [] }
]
}
]
}
]
how to change the array with new format like this
[
{
"id": 1,
"name": "selling",
},
{
"id": 11,
"name": "sale-report"
},
{ "id": 111, "name": "sale-report1" },
{ "id": 112, "name": "sale-report2" },
{
"id": 2,
"name": "webstore",
},
{
"id": 11,
"name": "sale-report",
},
{ "id": 111, "name": "webstore-report1" },
{ "id": 112, "name": "webstore-report2" },
{
"id": 2,
"name": "setting",
},
{
"id": 11,
"name": "general",
},
{ "id": 111, "name": "setting-general1" },
{ "id": 112, "name": "setting-general2" }
]
with the condition that if there is a key "detail" inside object in the branch, it will be mapped as well (assuming unlimited key "detail" inside object inside array)
note: content of detail will be same as parent, but different value
thanks in advance
i tried mapping mannualy with foreach, but i cant figure out if detail key with array(object) has unlimited nesting
Simply, use recursion to do this.
Here is the working demo-
let input = [
{
id: 1,
name: "selling",
detail: [
{
id: 11,
name: "sale-report",
detail: [
{ id: 111, name: "sale-report1", detail: [] },
{ id: 112, name: "sale-report2", detail: [] }
]
}
]
},
{
id: 2,
name: "webstore",
detail: [
{
id: 11,
name: "sale-report",
detail: [
{ id: 111, name: "webstore-report1", detail: [] },
{ id: 112, name: "webstore-report2", detail: [] }
]
}
]
},
{
id: 2,
name: "setting",
detail: [
{
id: 11,
name: "general",
detail: [
{ id: 111, name: "setting-general1", detail: [] },
{ id: 112, name: "setting-general2", detail: [] }
]
}
]
}
];
let result = [];
function parseData(arr) {
arr.forEach((item) => {
result.push({
id: item.id || null,
name: item.name || null
});
if (item.detail && item.detail.length) {
parseData(item.detail);
}
});
return result;
}
let output = parseData(input);
console.log(output);
You could destructure the objects and take detail out of the object and map the rest object and the results of nested details array as flat array with a recursive function.
const
flat = (array = []) => array.flatMap(({ detail, ...rest }) => [
rest,
...flat(detail)
]),
data = [{ id: 1, name: "selling", detail: [{ id: 11, name: "sale-report", detail: [{ id: 111, name: "sale-report1", detail: [] }, { id: 112, name: "sale-report2", detail: [] }] }] }, { id: 2, name: "webstore", detail: [{ id: 11, name: "sale-report", detail: [{ id: 111, name: "webstore-report1", detail: [] }, { id: 112, name: "webstore-report2", detail: [] }] }] }, { id: 2, name: "setting", detail: [{ id: 11, name: "general", detail: [{ id: 111, name: "setting-general1", detail: [] }, { id: 112, name: "setting-general2", detail: [] }] }] }],
result = flat(data);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
A non recursive method of doing this could look something like the following:
const data = [{"id":1,"name":"selling","detail":[{"id":11,"name":"sale-report","detail":[{"id":111,"name":"sale-report1","detail":[]},{"id":112,"name":"sale-report2","detail":[]}]}]},{"id":2,"name":"webstore","detail":[{"id":11,"name":"sale-report","detail":[{"id":111,"name":"webstore-report1","detail":[]},{"id":112,"name":"webstore-report2","detail":[]}]}]},{"id":2,"name":"setting","detail":[{"id":11,"name":"general","detail":[{"id":111,"name":"setting-general1","detail":[]},{"id":112,"name":"setting-general2","detail":[]}]}]}];
const extract = (data) => {
const result = [];
const queue = [...data];
while(queue.length > 0) {
const { detail, ...rest } = queue.shift();
result.push(rest);
queue.unshift(...detail);
}
return result;
};
console.log(extract(data));
I'm trying to filter an array with nested objects like this:
const items = [
{
"id": 1,
"name": "test1",
"subitems": [
{
"id": 2,
"name": "test2",
"subsubitems": [
{
"id": 3,
"name": "test3",
},
{
"id": 4,
"name": "test4",
}
]
}
]
},
{
"id": 10,
"name": "test10",
"subitems": [
{
"id": 20,
"name": "test20",
"subsubitems": [
{
"id": 30,
"name": "test30",
}
]
}
]
}
]
const filteredResults = items.filter((item) =>
item.subitems.filter((subitem) =>
subitem.subsubitems.filter((subsubitem) =>
subsubitem.name.includes('test3')
)
)
)
console.log(filteredResults)
But it's not filtering correctly, the original array is being returned. Right now I'm just attempting to filter at the subsubitems level. Ultimately I want to return an array with any matches to name at any level.
So test2 would return an array like this:
[
{
"id": 1,
"name": "test1",
"subitems": [
{
"id": 2,
"name": "test2",
"subsubitems": [
{
"id": 3,
"name": "test3",
},
{
"id": 4,
"name": "test4",
}
]
}
]
}
]
And test3 would return an array like this:
[
{
"id": 1,
"name": "test1",
"subitems": [
{
"id": 2,
"name": "test2",
"subsubitems": [
{
"id": 3,
"name": "test3",
}
]
}
]
}
]
And test would return everything.
Try This:
const items = [
{
id: 1,
name: "test1",
subitems: [
{
id: 2,
name: "test2",
subsubitems: [
{
id: 3,
name: "test3",
},
{
id: 4,
name: "test4",
},
],
},
],
},
{
id: 10,
name: "test10",
subitems: [
{
id: 20,
name: "test20",
subsubitems: [
{
id: 30,
name: "test30",
},
],
},
],
},
];
const filterItems = (items, filter) => {
const result = [];
items.forEach((item) => {
if (item.name === filter) {
result.push(item);
}
item.subitems.forEach((subitem) => {
if (subitem.name === filter) {
result.push(item);
}
subitem.subsubitems.forEach((subsubitem) => {
if (subsubitem.name === filter) {
result.push(item);
}
});
});
});
console.log("filtered", result);
};
filterItems(items, "test10");
Result is :
filtered [ { id: 10, name: 'test10', subitems: [ [Object] ] } ]
how can i convert returned data from this structure:
[
{
"id": 91,
"name": "Art",
"division": {
"id": 4,
"name": "1st level",
"created_at": "2018-11-05T10:11:37+00:00",
},
"created_at": "2018-11-05T10:11:37+00:00",
},
{
"id": 188,
"name": "English",
"division": {
"id": 9,
"name": "3rd level",
"created_at": "2018-11-05T10:11:37+00:00",
},
"created_at": "2018-11-05T10:11:37+00:00",
},
{
"id": 218,
"name": "Art",
"division": {
"id": 11,
"name": "3rd level",
"created_at": "2018-11-05T10:11:37+00:00",
},
"created_at": "2018-11-05T10:11:37+00:00",
}
]
to this structure :
[
{
"id": 1,
"name": "Art",
"classes": [
{
"id": 91,
"name": "1st level",
},
{
"id": 218,
"name": "3rd level",
},
],
},
{
"id": 2,
"name": "English",
"classes": [
{
"id": 188,
"name": "3rd level",
},
],
},
]
note: class.id = parentSubject.id
I wrote some codes to solve the problem but I'm looking for the best way !!
i use .reduce() function
I will attach the codes in the comments box.
Here is how I would do it:
let ans = initialArray.reduce((cum,x) => {
let foundIndex = cum.findIndex((a) =>{
return a.name == x.name});
if(foundIndex!=-1){
cum[foundIndex].classes.push({
id : x.id,
name : x.division.name
})
}
else{
cum.push({
id : cum.length+1,
name : x.name,
classes : [{
id : x.id,
name : x.division.name
}]
})
}
return cum;
},[]);
I use reduce and findIndex methods.
You can use array map to create a new array of objects with the new id.
const oldDatas = [
{
id: 91,
name: 'Art',
division: {
id: 4,
name: '1st level',
created_at: '2018-11-05T10:11:37+00:00',
},
created_at: '2018-11-05T10:11:37+00:00',
},
{
id: 188,
name: 'English',
division: {
id: 9,
name: '3rd level',
created_at: '2018-11-05T10:11:37+00:00',
},
created_at: '2018-11-05T10:11:37+00:00',
},
{
id: 218,
name: 'Art',
division: {
id: 11,
name: '3rd level',
created_at: '2018-11-05T10:11:37+00:00',
},
created_at: '2018-11-05T10:11:37+00:00',
},
];
const newDatas = oldDatas.map((data, index) => {
return { ...data, id: index + 1 };
});
console.log(newDatas);
my solution :
let res = initialArray.reduce((acc, obj) => {
const exist = acc.findIndex((item) => item.name === obj.name);
if (exist >= 0) {
acc[exist] = {
id: exist,
name: obj.name,
classes: [
...acc[exist].classes,
{ id: obj.id, name: obj.division.name },
],
};
} else {
acc.push({
id: acc.length,
name: obj.name,
classes: [{ id: obj.id, name: obj.division.name }],
});
}
return acc;
}, []);
Probably a basic question, but I've been blocked for a day now on this.
I am trying to get the correct map/filter from the following array:
[{
"id": 1,
"description": "Electric",
"subUtilityTypes": [{
"id": 5,
"description": "Grid"
},
{
"id": 6,
"description": "Solar"
}
]
},
{
"id": 2,
"description": "Gas",
"subUtilityTypes": [{
"id": 7,
"description": "Heating Oil"
},
{
"id": 8,
"description": "Natural Gas"
},
{
"id": 11,
"description": "Propane"
}
]
}
]
I want to get the id and description inside all subUtilityTypes.
This is what I've been trying:
this.options = arr1.map((parent) => {
return {
id: parent.id,
name: parent.subUtilityTypes.flatMap((child) => {
return child.description;
})
};
});
My problem with what I am trying is that instead of creating separate objects I am getting parent id and list of child names like this:
[{
"id": 1,
"name": [
"Grid",
"Solar"
]
},
{
"id": 2,
"name": [
"Heating Oil",
"Natural Gas",
"Propane"
]
}
]
Expected result should look like this:
[{
"id": 5,
"name": [
"Grid"
]
},
{
"id": 6,
"name": [
"Solar"
]
},
{
"id": 7,
"name": [
"Heating Oil"
]
}
]
Firstly use flatMap to get subUtilityTypes, then map entries:
const input = [{id:1,description:"Electric",subUtilityTypes:[{id:5,description:"Grid"},{id:6,description:"Solar"}]},{id:2,description:"Gas",subUtilityTypes:[{id:7,description:"Heating Oil"},{id:8,description:"Natural Gas"},{id:11,description:"Propane"}]}];
const res = input.flatMap(e => e.subUtilityTypes)
.map(e => ({ id: e.id, name: [e.description] }))
console.log(res)
.as-console-wrapper { max-height: 100% !important; top: 0; } /* ignore this */
Map only arr1 by returning only subUtilityTypes and then map it to get the desired result :
arr1.flatMap(item=>item.subUtilityTypes)
.map(item=>({id:item.id,name:[item.description]}))
let arr1=[
{
"id": 1,
"description": "Electric",
"subUtilityTypes": [
{
"id": 5,
"description": "Grid"
},
{
"id": 6,
"description": "Solar"
}
]
},
{
"id": 2,
"description": "Gas",
"subUtilityTypes": [
{
"id": 7,
"description": "Heating Oil"
},
{
"id": 8,
"description": "Natural Gas"
},
{
"id": 11,
"description": "Propane"
}
]
}
]
let options=arr1.flatMap(item=>item.subUtilityTypes).map(item=>({id:item.id,name:[item.description]}))
console.log(options)
You can also use reduce to achieve the same result.
arr.reduce((acc, curr) => [...acc,...curr.subUtilityTypes.map((o) => ({ id: o.id, name: [o.description] })),],[])
const arr = [
{
id: 1,
description: "Electric",
subUtilityTypes: [
{
id: 5,
description: "Grid",
},
{
id: 6,
description: "Solar",
},
],
},
{
id: 2,
description: "Gas",
subUtilityTypes: [
{
id: 7,
description: "Heating Oil",
},
{
id: 8,
description: "Natural Gas",
},
{
id: 11,
description: "Propane",
},
],
},
];
const result = arr.reduce((acc, curr) => [...acc,...curr.subUtilityTypes.map((o) => ({ id: o.id, name: [o.description] })),],[]);
console.log(result);
I have a list of elements like this
[{
"id": 1,
"id_team": "1.",
"name": "Name",
}, {
"id": 2,
"id_team": "2.",
"name": "Name",
}, {
"id": 3,
"id_team": "3.",
"name": "Name",
}, {
"id": 4,
"id_team": "4.",
"name": "Name",
}, {
"id": 5,
"id_team": "5.",
"name": "Name",
}, {
"id": 6,
"id_team": "2.1.",
"name": "Name",
}, {
"id": 7,
"id_team": "6.",
"name": "Name",
}, {
"id": 8,
"id_team": "1.1.",
"name": "Name",
}, {
"id": 9,
"id_team": "1.2.",
"name": "Name",
}, {
"id": 10,
"id_team": "1.3.",
"name": "Name",
}, {
"id": 11,
"id_team": "1.4.",
"name": "Name",
}]
a shown in the example, i have some string in the column id_team that are inside other string in the same column in the array
For example, the main team would be 1. then 1.1. and 1.2. and so on would be part of 1.
so the result must be like this
[{
"id": 1,
"id_team": "1.",
"name": "Name",
"subteams": [{
"id": 8,
"id_team": "1.1.",
"name": "Name",
}, {
"id": 9,
"id_team": "1.2.",
"name": "Name",
}, {
"id": 10,
"id_team": "1.3.",
"name": "Name",
}, {
"id": 11,
"id_team": "1.4.",
"name": "Name",
},],
}, {
"id": 2,
"id_team": "2.",
"name": "Name",
"subitems": [{
"id": 6,
"id_team": "2.1.",
"name": "Name",
},]
}, {
"id": 3,
"id_team": "3.",
"name": "Name",
"subitems": [],
}, {
"id": 4,
"id_team": "4.",
"name": "Name",
"subitems": [],
}, {
"id": 5,
"id_team": "5.",
"name": "Name",
"subitems": [],
}, {
"id": 7,
"id_team": "6.",
"name": "Name",
"subitems": [],
},]
it is doable? i use lodash if it would make it easier.
EDIT
I have something like this
teams.filter(item => item.id_team.length <= size).map((item) => {
const subteams = teams.filter((team) =>
team.id_team.indexOf(item.id_team) === 0 && item.id_team !== team.id_team);
console.log(subteams);
return {
...item,
subteams,
};
}) || [];
this kinda work, as it will insert in the sub teams array, but the problem is that this must work for many levels, take this example
[{
"id": 1,
"id_team": "1.",
"name": "Team Name",
"subteams": [{
"id": 8,
"id_team": "1.1.",
"name": "Team Name",
}, {
"id": 9,
"id_team": "1.2.",
"name": "Team Name",
}, {
"id": 10,
"id_team": "1.3.",
"name": "Team Name",
}, {
"id": 11,
"id_team": "1.4.",
"name": "Team Name",
}, {
"id": 12,
"id_team": "1.1.1",
"name": "Team Name",
}]
}, {
"id": 2,
"id_team": "2.",
"name": "Team Name",
"subteams": [{
"id": 6,
"id_team": "2.1.",
"name": "Team Name",
}]
}, {
"id": 3,
"id_team": "3.",
"name": "Team Name",
"subteams": []
}, {
"id": 4,
"id_team": "4.",
"name": "Team Name",
"subteams": []
}, {
"id": 5,
"id_team": "5.",
"name": "Team Name",
"subteams": []
}, {
"id": 7,
"id_team": "6.",
"name": "Team Name",
"subteams": []
}]
in this example there is a team with id_team = 1.1.1., how can i add that team to a sub team of the team with id_team 1.1. with the same logic, i tried to use the same code recursively but it didnt work.
const items = data.reduce((acc, item, index) => {
const id_team = item.id_team.split('.')[0] + '.';
const current = acc.find(record => record.id_team === id_team);
if(current) current.subteams.push(item);
else acc.push({
id: index + 1,
id_team,
subteams: [item]
});
return acc;
}, []);
let data = [{
"id": 1,
"id_team": "1.",
"name": "Name",
}, {
"id": 2,
"id_team": "2.",
"name": "Name",
}, {
"id": 3,
"id_team": "3.",
"name": "Name",
}, {
"id": 4,
"id_team": "4.",
"name": "Name",
}, {
"id": 5,
"id_team": "1.2.5.",
"name": "Name",
}, {
"id": 6,
"id_team": "2.1.",
"name": "Name",
}, {
"id": 7,
"id_team": "6.",
"name": "Name",
}, {
"id": 8,
"id_team": "1.1.",
"name": "Name",
}, {
"id": 9,
"id_team": "1.2.",
"name": "Name",
}, {
"id": 10,
"id_team": "1.3.",
"name": "Name",
}, {
"id": 11,
"id_team": "1.4.",
"name": "Name",
}];
data = data.map(node=>{
let t = node.id_team.split('.').filter(n=>n);
let parent = t.splice(0,t.length-1).join('.');
return {
...node,
parent: !!parent ? parent+'.' : null
}
});
let tree = (items, id = null) =>
items
.filter(item => item.parent === id)
.map(item => ({ ...item, subTeams: tree(items, item.id_team) }));
console.log(JSON.stringify(tree(data),null,2));
From the code of the example, i just checked if the subteams array has data, if it does, i use an auxiliar with the recursive function and assigned it to the subteams.
getSubTeams(teams, size) {
const filtered = teams.filter(item => item.id_team.length <= size);
return filtered.map((item) => {
let subteams = teams.filter((team) => team.id_team.indexOf(item.id_team) === 0 && item.id_team !== team.id_team);
if (subteams.length > 0) {
let aux = this.getSubTeams(subteams, size + 2);
subteams = [
...aux,
];
}
return {
...item,
subteams,
};
}) || [];
},