Related
I need to create a recursive function counting objects nested in the array where the selected attribute is true.
var data = [{"id":1,"code":"1","selected":false,"children":[{"id":4,"code":"1.01","selected":false,"children":[{"id":5,"code":"1.01.001","selected":true,"children":[]},{"id":6,"code":"1.01.002","selected":false,"children":[]},{"id":20,"code":"1.01.003","selected":true,"children":[]}]}]},{"id":2,"code":"2","selected":false,"children":[{"id":7,"code":"2.01","selected":false,"children":[{"id":9,"code":"2.01.001","selected":true,"children":[]},{"id":21,"code":"2.01.002","selected":true,"children":[]},{"id":22,"code":"2.01.003","selected":false,"children":[]}]}]},{"id":3,"code":"3","selected":false,"children":[{"id":8,"code":"3.01","selected":false,"children":[{"id":10,"code":"3.01.01","name":"Sementes","selected":false,"children":[{"id":11,"code":"3.01.01.001","selected":true,"children":[]},{"id":23,"code":"3.01.01.002","selected":false,"children":[]},{"id":24,"code":"3.01.01.003","selected":true,"children":[]}]},{"id":25,"code":"3.01.02","selected":false,"children":[{"id":27,"code":"3.01.02.001","selected":true,"children":[]},{"id":28,"code":"3.01.02.002","selected":false,"children":[]},{"id":29,"code":"3.01.02.003","selected":false,"children":[]}]},{"id":26,"code":"3.01.03","selected":false,"children":[{"id":30,"code":"3.01.03.001","selected":true,"children":[]},{"id":31,"code":"3.01.03.002","selected":true,"children":[]},{"id":32,"code":"3.01.03.003","selected":true,"children":[]},{"id":35,"code":"3.01.03.004","selected":false,"children":[]},{"id":34,"code":"3.01.03.005","selected":false,"children":[]}]}]}]}];
const countSelectedChildren = (arr) => {
return arr;
}
console.log(countSelectedChildren(data))
Expected response:
{
"id": 3,
"code": "3",
"selected": false,
"selectedChildren": 6,
"children": [
{
"id": 8,
"code": "3.01",
"selected": false,
"selectedChildren": 6,
"children": [
{
"id": 10,
"code": "3.01.01",
"name": "Sementes",
"selected": false,
"selectedChildren": 2,
"children": [
{
"id": 11,
"code": "3.01.01.001",
"selected": true,
"children": []
},
{
"id": 23,
"code": "3.01.01.002",
"selected": false,
"children": []
},
{
"id": 24,
"code": "3.01.01.003",
"selected": true,
"children": []
}
]
},
{
"id": 25,
"code": "3.01.02",
"selected": false,
"selectedChildren": 1,
"children": [
{
"id": 27,
"code": "3.01.02.001",
"selected": true,
"children": []
},
{
"id": 28,
"code": "3.01.02.002",
"selected": false,
"children": []
},
{
"id": 29,
"code": "3.01.02.003",
"selected": false,
"children": []
}
]
},
{
"id": 26,
"code": "3.01.03",
"selected": false,
"selectedChildren": 3,
"children": [
{
"id": 30,
"code": "3.01.03.001",
"selected": true,
"children": []
},
{
"id": 31,
"code": "3.01.03.002",
"selected": true,
"children": []
},
{
"id": 32,
"code": "3.01.03.003",
"selected": true,
"children": []
},
{
"id": 35,
"code": "3.01.03.004",
"selected": false,
"children": []
},
{
"id": 34,
"code": "3.01.03.005",
"selected": false,
"children": []
}
]
}
]
}
]
}
Can you help me to create this recursive function?
const countSelectedChildren = (arr) => {
return arr;
}
Thanks for your help!
You could take a recursive function for an array and return an object with a counting property and a children array.
const
addSelected = array => {
let selectedChildren = 0;
const
children = array.map(({ children, ...o }) => {
if (o.selected) selectedChildren++;
const temp = addSelected(children);
selectedChildren += temp.selectedChildren || 0;
return { ...o, ...temp };
});
return children.length
? { selectedChildren, children }
: { children };
},
data = [{ id: 1, code: "1", selected: false, children: [{ id: 4, code: "1.01", selected: false, children: [{ id: 5, code: "1.01.001", selected: true, children: [] }, { id: 6, code: "1.01.002", selected: false, children: [] }, { id: 20, code: "1.01.003", selected: true, children: [] }] }] }, { id: 2, code: "2", selected: false, children: [{ id: 7, code: "2.01", selected: false, children: [{ id: 9, code: "2.01.001", selected: true, children: [] }, { id: 21, code: "2.01.002", selected: true, children: [] }, { id: 22, code: "2.01.003", selected: false, children: [] }] }] }, { id: 3, code: "3", selected: false, children: [{ id: 8, code: "3.01", selected: false, children: [{ id: 10, code: "3.01.01", name: "Sementes", selected: false, children: [{ id: 11, code: "3.01.01.001", selected: true, children: [] }, { id: 23, code: "3.01.01.002", selected: false, children: [] }, { id: 24, code: "3.01.01.003", selected: true, children: [] }] }, { id: 25, code: "3.01.02", selected: false, children: [{ id: 27, code: "3.01.02.001", selected: true, children: [] }, { id: 28, code: "3.01.02.002", selected: false, children: [] }, { id: 29, code: "3.01.02.003", selected: false, children: [] }] }, { id: 26, code: "3.01.03", selected: false, children: [{ id: 30, code: "3.01.03.001", selected: true, children: [] }, { id: 31, code: "3.01.03.002", selected: true, children: [] }, { id: 32, code: "3.01.03.003", selected: true, children: [] }, { id: 35, code: "3.01.03.004", selected: false, children: [] }, { id: 34, code: "3.01.03.005", selected: false, children: [] }] }] }] }],
result = addSelected(data).children;
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Here's a fairly simple recursion to do this:
const sum = (ns) => ns .reduce ((a, b) => a + b, 0)
const countSelectedChildren = (xs) =>
xs .map (({children = [], ...rest}, _, __, kids = countSelectedChildren (children)) => ({
...rest,
...(children .length
? {selectedChildren: sum (kids .map (x => (x .selected ? 1 : 0) + (x .selectedChildren || 0)))}
: {}
),
children: kids,
}))
const data = [{"id":1,"code":"1","selected":false,"children":[{"id":4,"code":"1.01","selected":false,"children":[{"id":5,"code":"1.01.001","selected":true,"children":[]},{"id":6,"code":"1.01.002","selected":false,"children":[]},{"id":20,"code":"1.01.003","selected":true,"children":[]}]}]},{"id":2,"code":"2","selected":false,"children":[{"id":7,"code":"2.01","selected":false,"children":[{"id":9,"code":"2.01.001","selected":true,"children":[]},{"id":21,"code":"2.01.002","selected":true,"children":[]},{"id":22,"code":"2.01.003","selected":false,"children":[]}]}]},{"id":3,"code":"3","selected":false,"children":[{"id":8,"code":"3.01","selected":false,"children":[{"id":10,"code":"3.01.01","name":"Sementes","selected":false,"children":[{"id":11,"code":"3.01.01.001","selected":true,"children":[]},{"id":23,"code":"3.01.01.002","selected":false,"children":[]},{"id":24,"code":"3.01.01.003","selected":true,"children":[]}]},{"id":25,"code":"3.01.02","selected":false,"children":[{"id":27,"code":"3.01.02.001","selected":true,"children":[]},{"id":28,"code":"3.01.02.002","selected":false,"children":[]},{"id":29,"code":"3.01.02.003","selected":false,"children":[]}]},{"id":26,"code":"3.01.03","selected":false,"children":[{"id":30,"code":"3.01.03.001","selected":true,"children":[]},{"id":31,"code":"3.01.03.002","selected":true,"children":[]},{"id":32,"code":"3.01.03.003","selected":true,"children":[]},{"id":35,"code":"3.01.03.004","selected":false,"children":[]},{"id":34,"code":"3.01.03.005","selected":false,"children":[]}]}]}]}];
console .log (countSelectedChildren (data))
.as-console-wrapper {max-height: 100% !important; top: 0}
For each element in the input array recur first on any children, then to calculate the selectedChildren for our current node we sum up the results from each of our children, adding one for each if it's selected. Then we simply put back together a new object with selectedChildren included if we have actual children, with children the result of our recursion, and with the rest of the properties from our element.
While we could inline the one call to the sum helper function, it's something we're likely to want fairly often, so it's cleaner to keep it separate.
const countSelectedChildren = (data) => {
let length = 0;
for (item of data) {
item.selected && (length++)
let child_length = countSelectedChildren(item.children || [])[1];
length += child_length;
item.selectedChildren = child_length;
}
return [data, length];
}
I would approach it like this
const countSelectedChildren = (inArr) => {
const outArr = [];
inArr.forEach(row => {
// simply count all chilren with selected=true
row.SelectedChildren = row.children.filter(row => row.selected).length;
// if there are children, call this function on them
if (row.children.length) {
row.children = countSelectedChildren(row.children);
}
outArr.push(row);
});
return outArr;
}
const data = [
{
"id": 1,
"code": "1",
"selected": false,
"children": [
{
"id": 4,
"code": "1.01",
"selected": false,
"children": [
{
"id": 5,
"code": "1.01.001",
"selected": true,
"children": []
},
{
"id": 6,
"code": "1.01.002",
"selected": false,
"children": []
},
{
"id": 20,
"code": "1.01.003",
"selected": true,
"children": []
}
]
}
]
},
{
"id": 2,
"code": "2",
"selected": false,
"children": [
{
"id": 7,
"code": "2.01",
"selected": false,
"children": [
{
"id": 9,
"code": "2.01.001",
"selected": true,
"children": []
},
{
"id": 21,
"code": "2.01.002",
"selected": true,
"children": []
},
{
"id": 22,
"code": "2.01.003",
"selected": false,
"children": []
}
]
}
]
},
{
"id": 3,
"code": "3",
"selected": false,
"children": [
{
"id": 8,
"code": "3.01",
"selected": false,
"children": [
{
"id": 10,
"code": "3.01.01",
"name": "Sementes",
"selected": false,
"children": [
{
"id": 11,
"code": "3.01.01.001",
"selected": true,
"children": []
},
{
"id": 23,
"code": "3.01.01.002",
"selected": false,
"children": []
},
{
"id": 24,
"code": "3.01.01.003",
"selected": true,
"children": []
}
]
},
{
"id": 25,
"code": "3.01.02",
"selected": false,
"children": [
{
"id": 27,
"code": "3.01.02.001",
"selected": true,
"children": []
},
{
"id": 28,
"code": "3.01.02.002",
"selected": false,
"children": []
},
{
"id": 29,
"code": "3.01.02.003",
"selected": false,
"children": []
}
]
},
{
"id": 26,
"code": "3.01.03",
"selected": false,
"children": [
{
"id": 30,
"code": "3.01.03.001",
"selected": true,
"children": []
},
{
"id": 31,
"code": "3.01.03.002",
"selected": true,
"children": []
},
{
"id": 32,
"code": "3.01.03.003",
"selected": true,
"children": []
},
{
"id": 35,
"code": "3.01.03.004",
"selected": false,
"children": []
},
{
"id": 34,
"code": "3.01.03.005",
"selected": false,
"children": []
}
]
}
]
}
]
}
];
const countSelectedChildren = (inArr) => {
const outArr = [];
inArr.forEach(row => {
// simply count all chilren with selected=true
row.SelectedChildren = row.children.filter(row => row.selected).length;
// if there are children, call this function on them
if (row.children.length) {
row.children = countSelectedChildren(row.children);
}
outArr.push(row);
});
return outArr;
}
console.log(countSelectedChildren(data))
I'm having a hard time with this seemingly simple problem.
I understand that I can map through the main array and then map again through the items array but when I log the simpleObject variable I don't get anything returned.
I have an array of objects like this
[
{
"id": 131186,
"name": "Section",
"items": [
{
"id": 40455,
"categories": [
{
"id": 80313,
"name": "some name"
},
{
"id": 80314,
"name": "some name"
}
]
}
]
},
{
"id": 131279,
"name": "Section",
"items": [
{
"id": 40990,
"categories": [
{
"id": 82953,
"name": "category"
}
]
},
{
"id": 40991,
"categories": [
{
"id": 82952,
"name": "category title"
}
]
}
]
}
]
and I'm trying to build an array with the object that will look like this
[
{
"id": 131186,
"name": "Section",
"categories": [
{
"id": 80313,
"name": "some name"
},
{
"id": 80314,
"name": "some name"
}
]
},
{
"id": 131279,
"name": "Section",
"categories": [
{
"id": 82953,
"name": "category"
},
{
"id": 82952,
"name": "category title"
}
]
}
]
I tried the following but don't get any results back and not sure why.
let simpleObject = data.map(({ name, id, items }) => ({
id,
name,
items: items.map((item) => item.categories),
}));
An example using flatMap
const data = [ { id: 131186, name: "Section", items: [ { id: 40455, categories: [ { id: 80313, name: "some name", }, { id: 80314, name: "some name", }, ], }, ], }, { id: 131279, name: "Section", items: [ { id: 40990, categories: [ { id: 82953, name: "category", }, ], }, { id: 40991, categories: [ { id: 82952, name: "category title", }, ], }, ], }, ];
const output = data.map(({ id, name, items }) => ({
id,
name,
categories: items.flatMap(item => item.categories),
}));
console.log(output);
I've come up with this code which uses nested loops, trying to achieve the same result using array functions like filter, some, etc
https://jsfiddle.net/hw6of4je/
let availableItems = [{
"metric": "USD",
"code": "USDONE",
"quantity": "1"
}, {
"metric": "AUD",
"code": "AUDTHREE",
"quantity": "3"
}, {
"metric": "AFN",
"code": "AFNTWO",
"quantity": "1"
}, {
"metric": "ALL",
"code": "ALLSIX",
"quantity": "1"
}, {
"metric": "INR",
"code": "INRTWO",
"quantity": "1"
}]
const masterSet = [{
"uri": "marty-cruz.html",
"name": "marty-cruz",
"isVisible": false,
"skuCodes": ["USDONE", "USDTWO", "USDTHREE"]
}, {
"uri": "deanne-daniels.html",
"name": "deanne-daniels",
"isVisible": false,
"skuCodes": ["AUDONE", "AUDTWO", "AUDTHREE"]
}, {
"uri": "sallie-pachecok.html",
"name": "sallie-pachecok",
"isVisible": false,
"skuCodes": ["AFNTWO"]
}, {
"uri": "lillia-paul.html",
"name": "lillia-paul",
"isVisible": false,
"skuCodes": ["ALLONE", "ALLFOUR", "ALLSIX"]
}, {
"uri": "ken-johnston.html",
"name": "ken-johnston",
"isVisible": false,
"skuCodes": ["INRTWO"]
}, {
"uri": "mary-stanton.html",
"name": "mary-stanton",
"isVisible": false,
"skuCodes": ["RODEWQ667"]
}, {
"uri": "edwardo-brooks.html",
"name": "edwardo-brooks",
"isVisible": false,
"skuCodes": ["PADFER456"]
}]
let value = []
for (let item of availableItems) {
for (let mainItem of masterSet) {
if (mainItem.skuCodes.includes(item.code))
value.push(mainItem)
}
}
console.log(value)
If code from availableItems is present in one of the skuCodes of masterSet, I want that entry from masterSet in a new array.
Or the code I've come up with, is this the best way(readability and efficiency) this can be done.
This can be done in a single line - but it's not very readable and not very efficient:
let value = masterSet.filter(mi => availableItems.some(ai => mi.skuCodes.includes(ai.code)));
Live demo:
let availableItems = [{
"metric": "USD",
"code": "USDONE",
"quantity": "1"
}, {
"metric": "AUD",
"code": "AUDTHREE",
"quantity": "3"
}, {
"metric": "AFN",
"code": "AFNTWO",
"quantity": "1"
}, {
"metric": "ALL",
"code": "ALLSIX",
"quantity": "1"
}, {
"metric": "INR",
"code": "INRTWO",
"quantity": "1"
}]
const masterSet = [{
"uri": "marty-cruz.html",
"name": "marty-cruz",
"isVisible": false,
"skuCodes": ["USDONE", "USDTWO", "USDTHREE"]
}, {
"uri": "deanne-daniels.html",
"name": "deanne-daniels",
"isVisible": false,
"skuCodes": ["AUDONE", "AUDTWO", "AUDTHREE"]
}, {
"uri": "sallie-pachecok.html",
"name": "sallie-pachecok",
"isVisible": false,
"skuCodes": ["AFNTWO"]
}, {
"uri": "lillia-paul.html",
"name": "lillia-paul",
"isVisible": false,
"skuCodes": ["ALLONE", "ALLFOUR", "ALLSIX"]
}, {
"uri": "ken-johnston.html",
"name": "ken-johnston",
"isVisible": false,
"skuCodes": ["INRTWO"]
}, {
"uri": "mary-stanton.html",
"name": "mary-stanton",
"isVisible": false,
"skuCodes": ["RODEWQ667"]
}, {
"uri": "edwardo-brooks.html",
"name": "edwardo-brooks",
"isVisible": false,
"skuCodes": ["PADFER456"]
}]
let value = masterSet.filter(mi => availableItems.some(ai => mi.skuCodes.includes(ai.code)));
console.log(value);
Here is a solution:
let availableItems = [{
"metric": "USD",
"code": "USDONE",
"quantity": "1"
}, {
"metric": "AUD",
"code": "AUDTHREE",
"quantity": "3"
}, {
"metric": "AFN",
"code": "AFNTWO",
"quantity": "1"
}, {
"metric": "ALL",
"code": "ALLSIX",
"quantity": "1"
}, {
"metric": "INR",
"code": "INRTWO",
"quantity": "1"
}]
const masterSet = [{
"uri": "marty-cruz.html",
"name": "marty-cruz",
"isVisible": false,
"skuCodes": ["USDONE", "USDTWO", "USDTHREE"]
}, {
"uri": "deanne-daniels.html",
"name": "deanne-daniels",
"isVisible": false,
"skuCodes": ["AUDONE", "AUDTWO", "AUDTHREE"]
}, {
"uri": "sallie-pachecok.html",
"name": "sallie-pachecok",
"isVisible": false,
"skuCodes": ["AFNTWO"]
}, {
"uri": "lillia-paul.html",
"name": "lillia-paul",
"isVisible": false,
"skuCodes": ["ALLONE", "ALLFOUR", "ALLSIX"]
}, {
"uri": "ken-johnston.html",
"name": "ken-johnston",
"isVisible": false,
"skuCodes": ["INRTWO"]
}, {
"uri": "mary-stanton.html",
"name": "mary-stanton",
"isVisible": false,
"skuCodes": ["RODEWQ667"]
}, {
"uri": "edwardo-brooks.html",
"name": "edwardo-brooks",
"isVisible": false,
"skuCodes": ["PADFER456"]
}]
let value = []
availableItems.forEach((item)=>{
value.push(...(masterSet.filter((mainItem)=>(mainItem.skuCodes.includes(item.code)))))
})
console.log(value)
Try something like this one
const codes = availableItems.reduce((acc, {code}) => acc.add(code), new Set())
const value = masterSet.filter(({skuCodes}) => skuCodes.some((code) => codes.has(code)))
There is a more functional approach for sure. Whether it is better depends on your requirements. It may be less efficient but more readable and concise.
let test = masterSet.filter(x => availableItems.some(({ code }) => x.skuCodes.includes(code)))
let availableItems = [{
"metric": "USD",
"code": "USDONE",
"quantity": "1"
}, {
"metric": "AUD",
"code": "AUDTHREE",
"quantity": "3"
}, {
"metric": "AFN",
"code": "AFNTWO",
"quantity": "1"
}, {
"metric": "ALL",
"code": "ALLSIX",
"quantity": "1"
}, {
"metric": "INR",
"code": "INRTWO",
"quantity": "1"
}]
const masterSet = [{
"uri": "marty-cruz.html",
"name": "marty-cruz",
"isVisible": false,
"skuCodes": ["USDONE", "USDTWO", "USDTHREE"]
}, {
"uri": "deanne-daniels.html",
"name": "deanne-daniels",
"isVisible": false,
"skuCodes": ["AUDONE", "AUDTWO", "AUDTHREE"]
}, {
"uri": "sallie-pachecok.html",
"name": "sallie-pachecok",
"isVisible": false,
"skuCodes": ["AFNTWO"]
}, {
"uri": "lillia-paul.html",
"name": "lillia-paul",
"isVisible": false,
"skuCodes": ["ALLONE", "ALLFOUR", "ALLSIX"]
}, {
"uri": "ken-johnston.html",
"name": "ken-johnston",
"isVisible": false,
"skuCodes": ["INRTWO"]
}, {
"uri": "mary-stanton.html",
"name": "mary-stanton",
"isVisible": false,
"skuCodes": ["RODEWQ667"]
}, {
"uri": "edwardo-brooks.html",
"name": "edwardo-brooks",
"isVisible": false,
"skuCodes": ["PADFER456"]
}]
let test = masterSet.filter(x => availableItems.some(({ code }) => x.skuCodes.includes(code)))
console.log(test, test.length)
Yes, you can use the Array.prototype.filter to achieve that declaratively instead of writing imperative code using loops. I have done it in the below snippet.
Let me explain:
Array.prototype.filter takes in a callback function which can take upto 3 parameters - the current value, the current index and the array itself, we just want the current value. We want to filter the masterSet where availableItems has at least one of the values from masterSet, for which we use the Array.prototype.some( ) function. The filter() function returns an array, so we can directly store this filtered array into the value variable.
let value = masterSet.filter(item => {
return availableItems.some(avItem =>
item.skuCodes.includes(avItem.code));
});
let availableItems = [
{
metric: 'USD',
code: 'USDONE',
quantity: '1',
},
{
metric: 'AUD',
code: 'AUDTHREE',
quantity: '3',
},
{
metric: 'AFN',
code: 'AFNTWO',
quantity: '1',
},
{
metric: 'ALL',
code: 'ALLSIX',
quantity: '1',
},
{
metric: 'INR',
code: 'INRTWO',
quantity: '1',
},
];
const masterSet = [
{
uri: 'marty-cruz.html',
name: 'marty-cruz',
isVisible: false,
skuCodes: ['USDONE', 'USDTWO', 'USDTHREE'],
},
{
uri: 'deanne-daniels.html',
name: 'deanne-daniels',
isVisible: false,
skuCodes: ['AUDONE', 'AUDTWO', 'AUDTHREE'],
},
{
uri: 'sallie-pachecok.html',
name: 'sallie-pachecok',
isVisible: false,
skuCodes: ['AFNTWO'],
},
{
uri: 'lillia-paul.html',
name: 'lillia-paul',
isVisible: false,
skuCodes: ['ALLONE', 'ALLFOUR', 'ALLSIX'],
},
{
uri: 'ken-johnston.html',
name: 'ken-johnston',
isVisible: false,
skuCodes: ['INRTWO'],
},
{
uri: 'mary-stanton.html',
name: 'mary-stanton',
isVisible: false,
skuCodes: ['RODEWQ667'],
},
{
uri: 'edwardo-brooks.html',
name: 'edwardo-brooks',
isVisible: false,
skuCodes: ['PADFER456'],
},
];
let value = masterSet.filter(item => {
return availableItems.some(avItem =>
item.skuCodes.includes(avItem.code));
});
console.log(value);
One option would be to first flatten the codes to an array, and filter according to it:
const codes = masterSet.reduce((acc, cur) => acc.concat(cur.skuCodes), []);
const value = availableItems.filter(it => codes.includes(it.code));
Another approach would be to use a sort of hash map:
(Not the cleanest solution, could be improved)
const codes = masterSet.reduce((acc, cur) => {
const local = cur.skuCodes.reduce((a, c) => {
a[c] = 1;
return a;
}, {});
return {
...acc,
...local
}
}, {});
const value = availableItems.filter(it => codes[it.code])
I have two JSON strings as shown below:
source = [
{
"name": "test1",
"values": ["User Support"],
"enabled": false
},
{
"name": "test2",
"values": ["M"],
"enabled": true
},
{
"name": "test3",
"values": ["CA"],
"enabled": false
}
]
target = [{
"name": "test1",
"values": [{
"value": "User Support",
"selected": false
},
{
"value": "Engineering",
"selected": false
},
{
"value": "Implementation",
"selected": false
}
],
"enabled": false
},
{
"name": "test2",
"values": [{
"value": "M",
"selected": false
},
{
"value": "F",
"selected": false
}
],
"notEnabled": false
},
{
"name": "test3",
"values": [{
"value": "CA",
"selected": false
},
{
"value": "EN",
"selected": false
}
],
"enabled": false
}
]
I want to merge both these JSON strings into target and the resultant should look like:
target = [{
"name": "test1",
"values": [{
"value": "User Support",
"selected": true
},
{
"value": "Engineering",
"selected": false
},
{
"value": "Implementation",
"selected": false
}
],
"enabled": false
},
{
"name": "test2",
"values": [{
"value": "M",
"selected": true
},
{
"value": "F",
"selected": false
}
],
"enabled": true
},
{
"name": "test3",
"values": [{
"value": "CA",
"selected": true
},
{
"value": "EN",
"selected": false
}
],
"enabled": false
}
]
So, what I am trying to do is search in target string for name as test1, test2.... and then set the selected field as true if the value is found in source JSON string. Same is the case for enabled field.
First thing that comes to my mind is to use nested for each loops and check for the keys.
Is there any other better way to do this in Javascript?
Note that there could be other keys present inside target string, but we don't bother about them unless they are present in source string.
If you don't mind lodash:
const _ = require('lodash');
const sourceJSON = '[{"name":"test1","values":["User Support"],"enabled":false},{"name":"test2","values":["M"],"enabled":true},{"name":"test3","values":["CA"],"enabled":false}]';
const targetJSON = '[{"name":"test1","values":[{"value":"User Support","selected":false}, {"value":"Engineering","selected":false},{"value":"Implementation","selected":false}],"enabled":false},{"name":"test2","values":[{"value":"M","selected":false}, {"value":"F","selected":false} ],"notEnabled":false},{ "name":"test3","values": [{"value":"CA","selected":false},{"value":"EN","selected":false}],"enabled":false}]';
const source = JSON.parse(sourceJSON);
const target = JSON.parse(targetJSON);
const sourceNormalized = source.map((obj) => (
{ ...obj, values: [{value: obj.values[0], selected: true}] }
));
const merged = _.defaultsDeep(sourceNormalized, target);
console.dir(merged, {depth: null});
// [ { name: 'test1',
// values: [
// { value: 'User Support', selected: true },
// { value: 'Engineering', selected: false },
// { value: 'Implementation', selected: false }
// ],
// enabled: false
// },
// { name: 'test2',
// values: [
// { value: 'M', selected: true },
// { value: 'F', selected: false }
// ],
// enabled: true,
// notEnabled: false
// },
// { name: 'test3',
// values: [
// { value: 'CA', selected: true },
// { value: 'EN', selected: false }
// ],
// enabled: false} ]
result = JSON.stringify(merged);
The previous answer using lodash is a very good approach. In case you are in a situation such as myself (stuck working on a code-base where packages, including lodash, are difficult to get approved-for-use), here is an approach using Vanilla-javascript (+ JSON.stringify):
const delta = [{
"name": "test1",
"values": ["User Support"],
"enabled": false
},
{
"name": "test2",
"values": ["M"],
"enabled": true
},
{
"name": "test3",
"values": ["CA"],
"enabled": false
}
];
const orig = [{
"name": "test1",
"values": [{
"value": "User Support",
"selected": false
},
{
"value": "Engineering",
"selected": false
},
{
"value": "Implementation",
"selected": false
}
],
"enabled": false
},
{
"name": "test2",
"values": [{
"value": "M",
"selected": false
},
{
"value": "F",
"selected": false
}
],
"notEnabled": false
},
{
"name": "test3",
"values": [{
"value": "CA",
"selected": false
},
{
"value": "EN",
"selected": false
}
],
"enabled": false
}
];
const getTargetJSON = (delta, orig, debug = true) => { // method signature
const deltaMapper = delta.reduce((f, i) => ({
...f,
[i.name]: {
values: [...i.values],
enabled: i.enabled
}
}), {});
const target = orig.map(itm => ({
...itm,
values: itm.values.map(it2 => ({
...it2,
selected: deltaMapper[itm.name].values.includes(it2.value) || false
})),
enabled: deltaMapper[itm.name].enabled || false
}));
debug && console.log('Merged Target:\n', target);
return JSON.stringify(target);
};
getTargetJSON(delta, orig); // method call
Approach / Explanation:
We breakdown the problem into smaller ones.
First, generate a map using the source (named 'delta' in
code-snippet)
Next, iterate through the target (named 'orig') and utilize the
map (created above) to determine whether value is 'selected' and
item is 'enabled'.
I am parsing the JSON object. I want to set value which is stored in session against id. I have this JSON:
[
{
"id": "a",
"text": "a",
"icon": true,
"li_attr": {
"id": "a"
},
"a_attr": {
"href": "#"
},
"state": {
"loaded": true,
"opened": false,
"selected": false,
"disabled": false
},
"data": {
},
"children": [
]
},
{
"id": "b",
"text": "b\n ",
"icon": true,
"li_attr": {
"id": "b"
},
"a_attr": {
"href": "#"
},
"state": {
"loaded": true,
"opened": false,
"selected": false,
"disabled": false
},
"data": {
},
"children": [
{
"id": "b-a-1",
"text": "b-a",
"icon": true,
"li_attr": {
"id": "b-a-1"
},
"a_attr": {
"href": "#"
},
"state": {
"loaded": true,
"opened": false,
"selected": false,
"disabled": false
},
"data": {
},
"children": [
]
},
{
"id": "b-b-2",
"text": "b-b\n ",
"icon": true,
"li_attr": {
"id": "b-b-2"
},
"a_attr": {
"href": "#"
},
"state": {
"loaded": true,
"opened": false,
"selected": false,
"disabled": false
},
"data": {
},
"children": [
{
"id": "b-b-a",
"text": "b-b-a",
"icon": true,
"li_attr": {
"id": "b-b-a"
},
"a_attr": {
"href": "#"
},
"state": {
"loaded": true,
"opened": false,
"selected": false,
"disabled": false
},
"data": {
},
"children": [
]
},
{
"id": "b-b-b",
"text": "b-b-b",
"icon": true,
"li_attr": {
"id": "b-b-b"
},
"a_attr": {
"href": "#"
},
"state": {
"loaded": true,
"opened": false,
"selected": false,
"disabled": false
},
"data": {
},
"children": [
]
}
]
}
]
},
{
"id": "c-1",
"text": "c\n ",
"icon": true,
"li_attr": {
"id": "c-1"
},
"a_attr": {
"href": "#"
},
"state": {
"loaded": true,
"opened": false,
"selected": false,
"disabled": false
},
"data": {
},
"children": [
{
"id": "not-c-a-1",
"text": "c-a",
"icon": true,
"li_attr": {
"id": "not-c-a-1"
},
"a_attr": {
"href": "#"
},
"state": {
"loaded": true,
"opened": false,
"selected": false,
"disabled": false
},
"data": {
},
"children": [
]
},
{
"id": "not-c-b-2",
"text": "b-b",
"icon": true,
"li_attr": {
"id": "not-c-b-2"
},
"a_attr": {
"href": "#"
},
"state": {
"loaded": true,
"opened": false,
"selected": false,
"disabled": false
},
"data": {
},
"children": [
]
}
]
}
]
I want to make same type array having object. Inside the object there might be possibility of nested objects. I just want to set value against it id.
Can we get the information of children? If there are children, I need to set value. Here is my fiddle:
http://jsfiddle.net/fuu94/91/
$('#json').click(function(){
var json_list=$('#tree').jstree(true).get_json(); console.log(json_list.length);
for(var i=0;i<json_list.length;i++){
var obj={};
alert(json_list[i].id)
obj=sessionStorage.getItem(json_list[i].id);
arr[i]=obj;
}
console.log(arr)
})
});
Expected output is:
[
{
"a": "value_a",
"arr": [
]
},
{
"b": "value_b",
"arr": [
{
"b-a-1": "value_b-a-1",
"arr": [
]
},
{
"b-b-1": "value_b-b-2",
"arr": [
{
"b-b-a": "value_b-b-a",
"arr": [
]
},
{
"b-b-b": "value_b-b-b",
"arr": [
]
}
]
}
]
},
{
"c-1": "value_c-1",
"arr": [
{
"not-c-a-1": "value_not-c-a-1",
"arr": [
]
},
{
"not-c-b-2": "value_not-c-b-2",
"arr": [
]
}
]
}
]
You could use a reviver function that you pass to JSON.parse.
JSFIDDLE
var json = JSON.stringify([{ id: 'root', children: [ { id: 'nested' } ]}]);
var p = JSON.parse(json, function (k, v) {
if (!k) return v;
if (k === 'id' || k === 'children') return v;
if (+k == k && typeof v === 'object' && v != null && 'id' in v) {
v[v.id] = 'value_' + v.id;
delete v.id;
if (v.children) v.arr = v.children;
delete v.children;
return v;
}
});
JSON.stringify(p); //[{"root":"value_root","arr":[{"nested":"value_nested"}]}]
EDIT: I tried to make the code more robust by using a different approach, but it did not work as expected because the children key did not always came before we started to iterate over the array. Have a look at the edit history, perhaps I overlooked something.
Assuming that "b-b-1": "value_b-b-2" in the expected output is a type and really should be "b-b-2": "value_b-b-2" it should be very easy to map the original array to the expected output.
Use the map method on arrays (or, if you need to support older browsers, use the map implementation of some library you are using (e.g. jQuery or Underscore).
For each of the items in your array, you need to create an item which has two properties. The first property should be named according to the value of the id property of the input object and the value of the property seems like it should be the literal value_ followed by the value of the id property from the input object.
Furthermore, each item should also have an arr property, which is the result of applying our item mapping function to the items in the children array.
So the code could look something like
function mapItem(inputItem){
var item = {};
item[inputItem.id] = "value_" + inputItem.id;
item.arr = inputItem.children.map(mapItem);
return item;
};
var results = originalArray.map(mapItem);
I have the above mapping function running against your sample data at http://jsfiddle.net/tJ7Kq/