Group elements of array by sub string JavaScript - javascript

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,
};
}) || [];
},

Related

Is this the best approach to restructure an array and reorganize it based off a sub array's value

I have the below array which has a sub array of categories, I would like to output the array over and over but grouping the items into another array based on their related categories
testData2: any = [{
"id": 0,
"name": "XyZ",
"category": [ {
"title": "horse"
}, {
"title": "food"
}]
}, {
"id": 2,
"name": "something 2",
"category": [{
"title": "fishing"
}, {
"title": "horse"
}, {
"title": "food"
}]
},
{
"id": 3,
"name": "something 3",
"category": [{
"title": "horse"
}]
}, {
"id": 4,
"name": "something 4",
"category": [{
"title": "food"
}, {
"title": "beer"
}]
}, {
"id": 5,
"name": "something 4",
"category": [{
"title": "fishing"
}]
}
]
So far I have this which works, but i cant help wonder if there is some new JS magic which may be more perfomant to accomplish this ?
let newArray = [];
for (let x = 0; x < this.testData2.length; x++) {
let parent = this.testData2[x];
let child = parent.category;
for (let y = 0; y < child.length; y++) {
let cat = child[y];
let format = parent
newArray.push({ group_heading: cat.title, services: [format] })
}
}
let finalOutput = newArray.reduce((acc, curr) => {
const ndx = acc.findIndex((e: any) => e.group_heading === curr.group_heading);
if(ndx > -1){
acc[ndx].services.push(...curr.services)
} else{
acc.push(curr)
}
return acc;
}, [])
which outputs this as desired
[{
"group_heading": "horse",
"services": [{
"id": 0,
"name": "XyZ",
"category": [{
"title": "horse"
}, {
"title": "food"
}]
}, {
"id": 2,
"name": "something 2",
"category": [{
"title": "fishing"
}, {
"title": "horse"
}, {
"title": "food"
}]
}, {
"id": 3,
"name": "something 3",
"category": [{
"title": "horse"
}]
}]
}, {
"group_heading": "food",
"services": [{
"id": 0,
"name": "XyZ",
"category": [{
"title": "horse"
}, {
"title": "food"
}]
}, {
"id": 2,
"name": "something 2",
"category": [{
"title": "fishing"
}, {
"title": "horse"
}, {
"title": "food"
}]
}, {
"id": 4,
"name": "something 4",
"category": [{
"title": "food"
}, {
"title": "beer"
}]
}]
}, {
"group_heading": "fishing",
"services": [{
"id": 2,
"name": "something 2",
"category": [{
"title": "fishing"
}, {
"title": "horse"
}, {
"title": "food"
}]
}, {
"id": 5,
"name": "something 4",
"category": [{
"title": "fishing"
}]
}]
}, {
"group_heading": "beer",
"services": [{
"id": 4,
"name": "something 4",
"category": [{
"title": "food"
}, {
"title": "beer"
}]
}]
}]
I would probably do something like this:
// first collect services by category
const servicesByCategory = {}
for(const service of testData2){
for(const {title} of service.category){
if(!servicesByCategory[title]){
servicesByCategory[title] = []
}
servicesByCategory[title].push(data)
}
}
// whip it into whatever form you need
return Object.entries(servicesByCategory)
.map(([group_headings, services]) => ({group_headings, services}))

Find user details by ID in nested object nodejs | javascript

How to find name using id. means iterate object. create a function const searchName =()=>{}
suppose if pass 3 in function so I'd want to show .... what the name of user like this
const data = [{
"service": [
"BUSINESS",
"LEGAL",
"FINANCE",
"ADVERTISEMENT"
],
"service1": [
{ "id": 1, "name": "a" },
{ "id": 2, "name": "b" },
{ "id": 3, "name": "c" },
{ "id": 4, "name": "d" },
],
"service2": [
{ "id": 5, "name": "e" },
{ "id": 6, "name": "f" },
{ "id": 7, "name": "g" },
{ "id": 8, "name": "h" },
],
"service3": [
{ "id": 9, "name": "i" },
{ "id": 10, "name": "j" },
{ "id": 11, "name": "k" },
{ "id": 12, "name": "l" },
],
"service4": [
{ "id": 13, "name": "m" },
{ "id": 14, "name": "n" },
{ "id": 15, "name": "o" },
{ "id": 16, "name": "p" },
],
}
]
suppose user pass 3 so I want to return { "id": 3, "name": "c" } like this.
I'm trying to iterate this and find the name of the user by id but I didn't understand this iteration so I need your help.
check this code.... Enter any id number
const data = [{
"service": [
"BUSINESS",
"LEGAL",
"FINANCE",
"ADVERTISEMENT"
],
"service1": [
{ "id": 1, "name": "a" },
{ "id": 2, "name": "b" },
{ "id": 3, "name": "c" },
{ "id": 4, "name": "d" },
],
"service2": [
{ "id": 5, "name": "e" },
{ "id": 6, "name": "f" },
{ "id": 7, "name": "g" },
{ "id": 8, "name": "h" },
],
"service3": [
{ "id": 9, "name": "i" },
{ "id": 10, "name": "j" },
{ "id": 11, "name": "k" },
{ "id": 12, "name": "l" },
],
"service4": [
{ "id": 13, "name": "m" },
{ "id": 14, "name": "n" },
{ "id": 15, "name": "o" },
{ "id": 16, "name": "p" },
],
}]
var itemobj = ''
const searchName =(val)=>{
console.log('searchname')
data.map((item)=>{
let obj = Object.keys(item)
obj.map((data)=>{
let inrdata = item[data]
inrdata.map((initem)=>{
let lastdata = initem.id===val?itemobj=initem:null
})
})
})
}
searchName(3)
console.log(itemobj)
function searchName(id) {
let result = null;
for (const [key, value] of Object.entries(data)) {
if (key === "service") continue
result = value.filter(obj => {
return obj.id === id
})
if (result) break
}
return result ? result[0] : null
}
I iterate through keys, I just skip "service" one since it's not revelant.
Then, I filter the "serviceN" array, it will return an array of object (only one if found, empty array if not found).
If it's found, we stop iterating.
Then we return either the first (and logically only element) or null if not found
You could use a combination of flat and find to get get the user by id
function searchName(id) {
return data
.flatMap((item) => Object.values(item))
.flat()
.find((user) => user.id === id);
}
const result = searchName(3); // { id: 3, name: 'c' } | undefined

Filter nested objects by property value recursively and keep array structure

I have the following array of objects with nested elements in the children property. I need to get objects by their id if the id matches.
[
{
"id": 10,
"name": "Scenarios",
"value": null,
"children": [
{
"id": 12,
"name": "Scenario status",
"value": null,
"children": []
}
]
},
{
"id": 11,
"name": "Forecast source",
"value": null,
"children": []
},
{
"id": 16787217,
"name": "Item#Cust",
"value": null,
"children": [
{
"id": 16787230,
"name": "Customer",
"value": null,
"children": [
{
"id": 16787265,
"name": "Site",
"value": null,
"children": []
},
{
"id": 16787291,
"name": "Commercial Network",
"value": null,
"children": []
},
{
"id": 16787296,
"name": "Distribution Site",
"value": null,
"children": []
}
]
},
{
"id": 16787245,
"name": "Item#Site",
"value": null,
"children": [
{
"id": 16787266,
"name": "Family#Warehouse",
"value": null,
"children": []
}
]
},
{
"id": 16787254,
"name": "Item",
"value": null,
"children": [
{
"id": 16787260,
"name": "Family",
"value": null,
"children": [
{
"id": 16787264,
"name": "Product line",
"value": null,
"children": []
}
]
},
{
"id": 16787261,
"name": "Group 1",
"value": null,
"children": []
}
]
}
]
},
{
"id": 16787267,
"name": "Supplier",
"value": null,
"children": []
},
{
"id": 16787297,
"name": "SKU",
"value": null,
"children": []
}
]
If no match on root element is found, the function should lookup its children to see if there is a match, and the first children match should be pushed on the root level.
For exemple, I have a list of ids: [12, 16787217, 16787245, 16787266]
The function should return only objects where ids matches while keeping hierarchy if matching parent id have matching children id, so it should return this:
[
{
"id": 12,
"name": "Scenario status",
"value": null,
"children": []
},
{
"id": 16787217,
"name": "Item#Cust",
"value": null,
"children": [
{
"id": 16787245,
"name": "Item#Site",
"value": null,
"children": [
{
"id": 16787266,
"name": "Family#Warehouse",
"value": null,
"children": []
}
]
}
]
}
]
As for now, I can get only the first level elements if they are found with this function:
filterArray(array: Array<any>, ids: Array<number>) {
array = array.filter(el => ids.includes(el.id));
for (let i = 0; i < array.length; i++) {
this.filterArray(array[i].children, ids);
}
console.log(array);
}
Anyone have an idea on how to achieve this?
You could reduce the array and take the nodes with found id and children or only the children at the base level.
const
find = (r, { children = [], ...o }) => {
children = children.reduce(find, []);
if (ids.includes(o.id)) r.push({ ...o, children });
else if (children.length) r.push(...children);
return r;
},
data = [{ id: 10, name: "Scenarios", value: null, children: [{ id: 12, name: "Scenario status", value: null, children: [] }] }, { id: 11, name: "Forecast source", value: null, children: [] }, { id: 16787217, name: "Item#Cust", value: null, children: [{ id: 16787230, name: "Customer", value: null, children: [{ id: 16787265, name: "Site", value: null, children: [] }, { id: 16787291, name: "Commercial Network", value: null, children: [] }, { id: 16787296, name: "Distribution Site", value: null, children: [] }] }, { id: 16787245, name: "Item#Site", value: null, children: [{ id: 16787266, name: "Family#Warehouse", value: null, children: [] }] }, { id: 16787254, name: "Item", value: null, children: [{ id: 16787260, name: "Family", value: null, children: [{ id: 16787264, name: "Product line", value: null, children: [] }] }, { id: 16787261, name: "Group 1", value: null, children: [] }] }] }, { id: 16787267, name: "Supplier", value: null, children: [] }, { id: 16787297, name: "SKU", value: null, children: [] }],
ids = [12, 16787217, 16787245, 16787266],
result = data.reduce(find, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could also try this
let data = [
{
"id": 10,
"name": "Scenarios",
"value": null,
"children": [
{
"id": 12,
"name": "Scenario status",
"value": null,
"children": []
}
]
},
{
"id": 11,
"name": "Forecast source",
"value": null,
"children": []
},
{
"id": 16787217,
"name": "Item#Cust",
"value": null,
"children": [
{
"id": 16787230,
"name": "Customer",
"value": null,
"children": [
{
"id": 16787265,
"name": "Site",
"value": null,
"children": []
},
{
"id": 16787291,
"name": "Commercial Network",
"value": null,
"children": []
},
{
"id": 16787296,
"name": "Distribution Site",
"value": null,
"children": []
}
]
},
{
"id": 16787245,
"name": "Item#Site",
"value": null,
"children": [
{
"id": 16787266,
"name": "Family#Warehouse",
"value": null,
"children": []
}
]
},
{
"id": 16787254,
"name": "Item",
"value": null,
"children": [
{
"id": 16787260,
"name": "Family",
"value": null,
"children": [
{
"id": 16787264,
"name": "Product line",
"value": null,
"children": []
}
]
},
{
"id": 16787261,
"name": "Group 1",
"value": null,
"children": []
}
]
}
]
},
{
"id": 16787267,
"name": "Supplier",
"value": null,
"children": []
},
{
"id": 16787297,
"name": "SKU",
"value": null,
"children": []
}
]
let ids = [12, 16787217, 16787245, 16787266]
let filterArray = (mArray, ids) => {
let result = []
for (const x of mArray) {
if (ids.includes(x.id)) {
let element = {...x, children: []}
let childrenFounds = []
if (x.children.length) {
childrenFounds = filterArray(x.children, ids)
if (childrenFounds.length) element.children.push(...childrenFounds)
}else {
delete element.children
}
result.push(element)
} else if (x.children.length) {
let found = filterArray(x.children, ids)
if (found.length) result.push(...found)
}
}
return result
}
let res = filterArray(data, ids)
console.log('res', res)

Reduce it array to an easier way to map

I'm developing an application and have added new items to my array: type and description.
array = [
{
"id": 1,
"description": "item1",
"date": {
"id": 1,
"name": "202001"
},
"item": {
"id": 1,
"name": "I1"
},
"type": {
"id": 1,
"name": "type1"
},
"price": 100
},
{
"id": 2,
"description": "item1",
"date": {
"id": 2,
"name": "202002"
},
"item": {
"id": 1,
"name": "I1"
},
"type": {
"id": 1,
"name": "type1"
},
"price": 200
},
{
"id": 3,
"description": "item1",
"date": {
"id": 2,
"name": "202002"
},
"item": {
"id": 2,
"name": "I2"
},
"type": {
"id": 2,
"name": "type2"
},
"price": 300
},
]
I previously did this to reduce it down to an easier way to map it:
items = array.reduce((acc, e) => {
if (!acc[e["item"]["name"]]) {
acc[e["item"]["name"]] = {
[e["date"]["name"]]: e["price"]
}
} else {
acc[e["item"]["name"]][e["date"]["name"]] = e["price"]
}
return acc
}, {})
To show the data before I did
const dates = [...new Set(Object.keys(items_dicc).map(i => Object.keys(items_dicc[i])).flat())]
{
Object.keys(items_dicc).map((item) => {
return (
<tr>
<td>{item}</td>
{dates.map((date) => <td>{items_dicc[item][date] || ''}</td>)}
</tr>
)
})
}
I need to add the description element and type.name to the above. For example for description:
description: e["description"]
To display the elements as in the table:
ITEM
DESCRIPTION
TYPE
202001
202002
I1
item1
type1
100
200
I2
item3
type2
-
300
How do I add and show?
EDIT: console.log(items_dicc[item])
{202001: 100, 202002: 200, description: "item1", type: "type1"}
202001: 100
202002: 200
description: "item1"
type: "type1"
__proto__: Object
{202002: 300, description: "item3", type: "type2"}
202002: 300
description: "item3"
type: "type2"
__proto__: Object
You can add the description and type attribute inside the reduce method like this,
array = [
{
"id": 1,
"description": "item1",
"date": {
"id": 1,
"name": "202001"
},
"item": {
"id": 1,
"name": "I1"
},
"type": {
"id": 1,
"name": "type1"
},
"price": 100
},
{
"id": 2,
"description": "item2",
"date": {
"id": 2,
"name": "202002"
},
"item": {
"id": 1,
"name": "I1"
},
"type": {
"id": 1,
"name": "type1"
},
"price": 200
},
{
"id": 3,
"description": "item3",
"date": {
"id": 2,
"name": "202002"
},
"item": {
"id": 2,
"name": "I2"
},
"type": {
"id": 2,
"name": "type2"
},
"price": 300
},
]
items = array.reduce((acc, e) => {
if (!acc[e["item"]["name"]]) {
acc[e["item"]["name"]] = {
[e["date"]["name"]]: e["price"],
'description': e['description'],
'type': e.type?.name,
}
} else {
acc[e["item"]["name"]][e["date"]["name"]] = e["price"]
}
return acc
}, {})
console.log(items);
To add the for description and name in the table,
const dates = [...new Set(Object.keys(items_dicc).map(i => Object.keys(items_dicc[i])).flat())]
{
Object.keys(items_dicc).map((item) => {
return (
<tr>
<td>{item}</td>
<td>{items_dicc[item]?.description}</td>
<td>{items_dicc[item]?.type}</td>
{dates.map((date) => <td>{items_dicc[item][date] || ''}</td>)}
</tr>
)
})
}
I have been seeing your question regarding these type of tables from yesterday. You have posted several questions with similar things. I suggest you to read some article and understand how JS array methods works instead of asking incremental questions in SO.
Asking in SO might solve your problems for now, but in the long run you will suffer as you don't seem to have a grip on how these things works.
you can simplify your solution like this.
const array = [{
"id": 1,
"description": "item1",
"date": {
"id": 1,
"name": "202001"
},
"item": {
"id": 1,
"name": "I1"
},
"type": {
"id": 1,
"name": "type1"
},
"price": 100
},
{
"id": 2,
"description": "item2",
"date": {
"id": 2,
"name": "202002"
},
"item": {
"id": 1,
"name": "I1"
},
"type": {
"id": 1,
"name": "type1"
},
"price": 200
},
{
"id": 3,
"description": "item3",
"date": {
"id": 2,
"name": "202002"
},
"item": {
"id": 2,
"name": "I2"
},
"type": {
"id": 2,
"name": "type2"
},
"price": 300
}
]
const result = array.map(item => {
return Object.keys(item).reduce((a, c) => {
if (c === "date") {
a[item[c].name] = item.price;
} else if (c !== "price" && c !== "id") {
a[c] = (typeof item[c] === "object") ? item[c].name : item[c];
}
return a;
}, {})
});
console.log(result);

How to remove all empty array childrens [] from a nested JSON recursively [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I've a JSON response as below.I'm using nested JSON data from my GeoRegionCountries APIController & custom class TreeView is used to format the data as per the required nested structure of plugin I'm using. I am using a combo multi select Treeview using this jquery plugin Multi-Select Drop Down Tree Plugin you can see it by this link jquery plugin Multi-Select Drop Down Tree Plugin
[
{
"Id": 1,
"Title": "United States",
"ParentId": null,
"Subs": [
{
"Id": 7,
"Title": "Northwest",
"ParentId": 1,
"Subs": []
},
{
"Id": 8,
"Title": "Northeast",
"ParentId": 1,
"Subs": []
},
{
"Id": 9,
"Title": "Central",
"ParentId": 1,
"Subs": []
},
{
"Id": 10,
"Title": "Southwest",
"ParentId": 1,
"Subs": []
},
{
"Id": 18,
"Title": "Southeast",
"ParentId": 1,
"Subs": []
}
]
},
{
"Id": 2,
"Title": "Canada",
"ParentId": null,
"Subs": []
},
{
"Id": 3,
"Title": "France",
"ParentId": null,
"Subs": []
},
{
"Id": 4,
"Title": "Germany",
"ParentId": null,
"Subs": []
},
{
"Id": 5,
"Title": "Australia",
"ParentId": null,
"Subs": []
},
{
"Id": 6,
"Title": "United Kingdom",
"ParentId": null,
"Subs": []
}
]
I want to remove all "Subs" with empty array.
[
{
"Id": 1,
"Title": "United States",
"ParentId": null,
"Subs": [
{
"Id": 7,
"Title": "Northwest",
"ParentId": 1
},
{
"Id": 8,
"Title": "Northeast",
"ParentId": 1
},
{
"Id": 9,
"Title": "Central",
"ParentId": 1
},
{
"Id": 10,
"Title": "Southwest",
"ParentId": 1
},
{
"Id": 18,
"Title": "Southeast",
"ParentId": 1
}
]
},
{
"Id": 2,
"Title": "Canada",
"ParentId": null
},
{
"Id": 3,
"Title": "France",
"ParentId": null
},
{
"Id": 4,
"Title": "Germany",
"ParentId": null
},
{
"Id": 5,
"Title": "Australia",
"ParentId": null
},
{
"Id": 6,
"Title": "United Kingdom",
"ParentId": null
}
]
What is the best way to deep clean this? I tried different solutions in Stackopverflow but all i got is Object object in place of empty Subs - which i don't want.
[
{
"Id": 1,
"Title": "United States",
"ParentId": null,
"Subs": [
{
"Id": 7,
"Title": "Northwest",
"ParentId": 1,
Object object
},
{
"Id": 8,
"Title": "Northeast",
"ParentId": 1,
Object object
},
{
"Id": 9,
"Title": "Central",
"ParentId": 1,
Object object
},
{
"Id": 10,
"Title": "Southwest",
"ParentId": 1,
Object object
},
{
"Id": 18,
"Title": "Southeast",
"ParentId": 1,
Object object
}
]
},
{
"Id": 2,
"Title": "Canada",
"ParentId": null,
Object object
},
{
"Id": 3,
"Title": "France",
"ParentId": null,
Object object
},
{
"Id": 4,
"Title": "Germany",
"ParentId": null,
Object object
},
{
"Id": 5,
"Title": "Australia",
"ParentId": null,
Object object
},
{
"Id": 6,
"Title": "United Kingdom",
"ParentId": null,
Object object
}
]
which is not i want
You can use _.transform() to recursively check for a specific key (Subs), and remove it if it's value is empty:
const { transform, isObject, isEmpty } = _;
const removeEmpty = (obj, key) =>
transform(obj, (r, v, k) => {
if(k === key && isEmpty(v)) return;
r[k] = isObject(v) ? removeEmpty(v, key) : v;
});
const tree = [{"Id":1,"Title":"United States","ParentId":null,"Subs":[{"Id":7,"Title":"Northwest","ParentId":1,"Subs":[]},{"Id":8,"Title":"Northeast","ParentId":1,"Subs":[]},{"Id":9,"Title":"Central","ParentId":1,"Subs":[]},{"Id":10,"Title":"Southwest","ParentId":1,"Subs":[]},{"Id":18,"Title":"Southeast","ParentId":1,"Subs":[]}]},{"Id":2,"Title":"Canada","ParentId":null,"Subs":[]},{"Id":3,"Title":"France","ParentId":null,"Subs":[]},{"Id":4,"Title":"Germany","ParentId":null,"Subs":[]},{"Id":5,"Title":"Australia","ParentId":null,"Subs":[]},{"Id":6,"Title":"United Kingdom","ParentId":null,"Subs":[]}]
const result = removeEmpty(tree, 'Subs');
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
The correct answer would be this:
let array = [
{
'Id': 1,
'Title': 'United States',
'ParentId': null,
'Subs': [
{
'Id': 7,
'Title': 'Northwest',
'ParentId': 1,
'Subs': []
},
{
'Id': 8,
'Title': 'Northeast',
'ParentId': 1,
'Subs': []
},
{
'Id': 9,
'Title': 'Central',
'ParentId': 1,
'Subs': []
},
{
'Id': 10,
'Title': 'Southwest',
'ParentId': 1,
'Subs': []
},
{
'Id': 18,
'Title': 'Southeast',
'ParentId': 1,
'Subs': []
}
]
},
{
'Id': 2,
'Title': 'Canada',
'ParentId': null,
'Subs': []
},
{
'Id': 3,
'Title': 'France',
'ParentId': null,
'Subs': []
},
{
'Id': 4,
'Title': 'Germany',
'ParentId': null,
'Subs': []
},
{
'Id': 5,
'Title': 'Australia',
'ParentId': null,
'Subs': []
},
{
'Id': 6,
'Title': 'United Kingdom',
'ParentId': null,
'Subs': []
}
]
let newArray = array.map(item=> {
if (item.Subs.length===0){
delete item.Subs
return item
}
item.Subs = item.Subs.map(item=>{
if (item.Subs.length===0){
delete item.Subs
return item
}
})
return item
}
)
console.log(newArray)
let data = [
{
"Id": 1,
"Title": "United States",
"ParentId": null,
"Subs": [
{
"Id": 7,
"Title": "Northwest",
"ParentId": 1,
"Subs": []
},
{
"Id": 8,
"Title": "Northeast",
"ParentId": 1,
"Subs": []
},
{
"Id": 9,
"Title": "Central",
"ParentId": 1,
"Subs": []
},
{
"Id": 10,
"Title": "Southwest",
"ParentId": 1,
"Subs": []
},
{
"Id": 18,
"Title": "Southeast",
"ParentId": 1,
"Subs": []
}
]
},
{
"Id": 2,
"Title": "Canada",
"ParentId": null,
"Subs": []
},
{
"Id": 3,
"Title": "France",
"ParentId": null,
"Subs": []
},
{
"Id": 4,
"Title": "Germany",
"ParentId": null,
"Subs": []
},
{
"Id": 5,
"Title": "Australia",
"ParentId": null,
"Subs": []
},
{
"Id": 6,
"Title": "United Kingdom",
"ParentId": null,
"Subs": []
}
];
data = data.map(row=>{
if (!row.Subs.length) {
let {Subs,...r} = row;
return r;
} return row
})
console.log(data);
write two functions and pass the function that iterates through your array to a map function on data as shown below
function formatData(val) {
if (val.Subs.length > 0) val.Subs.map(a => a.Subs.length > 0 ? formatData(a.Subs) : deleteSubs(a));
else deleteSubs(val);
return val;
}
function deleteSubs(val) {
delete val.Subs;
}
var data = [{
"Id": 1,
"Title": "United States",
"ParentId": null,
"Subs": [{
"Id": 7,
"Title": "Northwest",
"ParentId": 1,
"Subs": []
},
{
"Id": 8,
"Title": "Northeast",
"ParentId": 1,
"Subs": []
},
{
"Id": 9,
"Title": "Central",
"ParentId": 1,
"Subs": []
},
{
"Id": 10,
"Title": "Southwest",
"ParentId": 1,
"Subs": []
},
{
"Id": 18,
"Title": "Southeast",
"ParentId": 1,
"Subs": []
}
]
},
{
"Id": 2,
"Title": "Canada",
"ParentId": null,
"Subs": []
},
{
"Id": 3,
"Title": "France",
"ParentId": null,
"Subs": []
},
{
"Id": 4,
"Title": "Germany",
"ParentId": null,
"Subs": []
},
{
"Id": 5,
"Title": "Australia",
"ParentId": null,
"Subs": []
},
{
"Id": 6,
"Title": "United Kingdom",
"ParentId": null,
"Subs": []
}
]
console.log(data.map(formatData))

Categories