I have json nested array as follows:
Parent: {
Child1: [
{name:'grandchild1', value:'abc', checked:true},
{name:'grandchild2', value:'pqr', checked:false}
],
Child2: [
{name:'grandchild3', value:'abcd', checked:false},
{name:'grandchild4', value:'pqrs', checked:true}
],
parent2{...........}....
};
I need to convert it into:
[
{
"filename":"Parent",
"children":[
{
"filename":"Child1",
"children":[
{
"filename":"grandchild1",
"type":"ts"
},
{
"filename":"grandchild2",
"type":"ts"
}
]
},
{
"filename":"Child2",
"children":[
{
"filename":"grandchild3",
"type":"ts"
},
{
"filename":"grandchild4",
"type":"ts"
}
]
}
]
},
{ filename:"Parent1"..........
},....
]
It is a part of angular material tree. They have sample code Link
Tried with below code:
Object.keys(obj).reduce<FileNode[]>((accumulator, key) => {
const value = obj[key];
const node = new FileNode();
node.filename = key;
if (value != null) {
if (typeof value === 'object') {
node.children = this.buildFileTree(value, level + 1);
} else {
node.type = value;
}
}
return accumulator.concat(node);
}, []);
}
But not getting what I need.
Please suggest me how can I convert into the following format so that it will accept the corresponding way?
You can use the for of and for in functions
const list = {Parent1 :{
Child1: [
{name:'grandchild1', value:'abc', checked:true},
{name:'grandchild2', value:'pqr', checked:false}
] ,
Child2: [
{name:'grandchild3', value:'abcd', checked:false},
{name:'grandchild4', value:'pqrs', checked:true}
]
}, Parent2 :{
Child1: [
{name:'grandchild1', value:'abc', checked:true},
{name:'grandchild2', value:'pqr', checked:false}
] ,
Child2: [
{name:'grandchild3', value:'abcd', checked:false},
{name:'grandchild4', value:'pqrs', checked:true}
]
}};
const res = []
for(let parent in list){
let parentTemp = {
filename : parent,
children : []
}
for(let child in list[parent]){
let childTemp = {filename : child, children : []};
for(let grandChild of list[parent][child]){
childTemp.children.push({filename : grandChild.name, type : grandChild.value, status: grandChild.checked});
}
parentTemp.children.push(childTemp);
}
res.push(parentTemp);
}
console.log(res);
Related
I am getting an array of object data from service as below:
outputs
array= [
{id:1,Name:GHI,Gender:Male,DOB:12/1/2020},
{id:1,Name:GHI,Gender:Female,DOB:10/1/2020},
{id:2,Name:ABC,Gender:Male,DOB:02/02/2020},
{id:2,Name:ABC,Gender:Female,DOB:03/04/2019},
{id:3,Name:EFG,Gender:Male,DOB:09/09/2010},
{id:3,Name:EFG,Gender:Female,DOB:08/07/2021}
]
I have applied group by function and mapping by using the key
let key="id";
const groupBy=(array,key)=>{
return Object.entries(array.reduce((result,currentvalue)=>{
(result[currentValues[key]]=result[currentValue[key]]||[]).push(
currentvalue
);
return result;
},{})).map(v=>({[key]:v[0],data:v[1]})));
};
I am able to get data like this
[
{
Id:1,
data:
[
{id:1,Name:GHI,Gender:Male,DOB:12/1/2020},
{id:1,Name:GHI,Gender:Female,DOB:10/1/2020}
]
},
{
Id:2,
data:
[
{id:2,Name:ABC,Gender:Male,DOB:02/02/2020},
{id:2,Name:ABC,Gender:Female,DOB:03/04/3019}
]
}...
]
But I need the out put some thing like this I need to group by Id but need the Name of Id something like this
[
{
Name:GHI,
data:[
{id:1,Name:GHI,Gender:Male,DOB:12/1/2020},
{id:1,Name:GHI,Gender:Female,DOB:10/01/2020}
]
},
{
Name:ABC,
data:[
{id:2,Name:ABC,Gender:Male,DOB:02/02/2020},
{id:2,Name:ABC,Gender:Female,DOB:03/04/2019}
]
},
{
Name:EFG,
data:[
{id:3,Name:EFG,Gender:Male,DOB:09/09/2010},
{id:3,Name:EFG,Gender:Male,DOB:08/07/2021}
]
}
]
Please let me know how to retrieve data in expected format to display on UI.
try with the below code.
var arr = [
{id:1,Name:"GHI",Gender:"Male",DOB:"12/1/2020"},
{id:1,Name:"GHI",Gender:"Female",DOB:"10/1/2020"},
{id:2,Name:"ABC",Gender:"Male",DOB:"02/02/2020"},
{id:2,Name:"ABC",Gender:"Female",DOB:"03/04/2019"},
{id:3,Name:"EFG",Gender:"Male",DOB:"09/09/2010"},
{id:3,Name:"EFG",Gender:"Female",DOB:"08/07/2021"}
]
let temp = {}
arr.forEach((obj) => {
temp[obj.Name] = temp[obj.Name] || [];
temp[obj.Name].push(obj);
});
let output = Object.entries(temp).map(obj => {
return {"Name": obj[0], "data": obj[1]}
});
console.log(JSON.stringify(output, null, 2));
You may go simpler and more readable:
let result = {};
for (const data of array) {
const { Name } = data;
if (!result[Name]) {
result[Name] = { Name, data: [data] };
} else {
result[Name].data.push(data);
}
}
I have an array of objects, where each object has a property (parentsList) indicating the category the current item belongs to, something like:
const data = [
{
...other properties,
"parentsList": [
"Assets",
"Icons"
],
},
{
...other properties,
"parentsList": [
"Assets",
"Fonts"
],
},
{
...other properties,
"parentsList": [
"Programming",
"JavaScript",
"Docs"
],
},
{
...other properties,
"parentsList": [
"Programming",
"JavaScript",
"React",
"Libraries",
],
},
]
That means the first object belongs to assets/icons, the second to assets/fonts, third to programming/javascript/docs and so on.
I'm trying to map it to a tree-like view, where siblings should be under the same parent, something like:
const data = [
{
name: 'Assets',
id: 'assets',
children: [
{
name: 'Icons',
id: 'assets/icons',
},
{
name: 'Illustrations',
id: 'assets/illustrations',
},
],
},
{
name: 'Programming',
id: 'programming',
children: [
{
name: 'JavaScript',
id: 'programming/javascript',
children: [
{
name: 'Docs',
id: 'programming/javascript/docs',
},
{
name: 'React',
id: 'programming/javascript/react',
children: [
{
name: 'Libraries',
id: 'programming/javascript/react/libraries',
},
],
},
],
},
],
},
]
I imagine it's gonna be easier to traverse from the right, maybe with reduceRight(), but I can't seem to get it right.
Anyone would know how to achieve that?
Thanks!
I tend to avoid using reduce because I find it difficult to read the code that has reduce in it. So, here is a non-reduce way.
const data = [
{
parentsList: [
"Assets",
"Icons"
],
},
{
parentsList: [
"Assets",
"Fonts"
],
},
{
parentsList: [
"Programming",
"JavaScript",
"Docs"
],
},
{
parentsList: [
"Programming",
"JavaScript",
"React",
"Libraries",
],
},
];
const processedData = [];
for (const item of data) {
const parents = [...item.parentsList].reverse();
let children = processedData;
const ids = [];
while (parents.length > 0) {
const parent = parents.pop();
ids.push(parent.toLowerCase());
let foundParent = false;
for (const child of children) {
if (child.name === parent) {
children = child.children;
foundParent = true;
break;
}
}
if (!foundParent) {
const newChild = {name: parent, id: ids.join("/"), children: [],};
children.push(newChild);
children = newChild.children;
}
}
}
console.log(processedData);
You can do this as a combination of forEach and reduce and create a nested hierarchy based on the parentsList array.
const data = [{"parentsList":["Assets","Icons"]},{"parentsList":["Assets","Fonts"]},{"parentsList":["Programming","JavaScript","Docs"]},{"parentsList":["Programming","JavaScript","React","Libraries"]}]
const result = []
data.forEach(function({ parentsList, ...rest }) {
let id = '';
parentsList.reduce((r, name, i) => {
id += (id.length ? '/' : '') + name.toLowerCase();
if (!r[name]) {
const value = { id, name }
r[name] = {result: []}
if (i != parentsList.length - 1) {
value.children = r[name].result
} else {
Object.assign(value, rest)
}
r.result.push(value)
}
return r[name]
}, this)
}, {result})
console.log(result)
A short approach by using nested objects as hash tables.
const
data = [{ parentsList: ["Assets", "Icons"] }, { parentsList: ["Assets", "Fonts"] }, { parentsList: ["Programming", "JavaScript", "Docs"] }, { parentsList: ["Programming", "JavaScript", "React", "Libraries"] }],
tree = data.reduce((t, { parentsList }) => {
parentsList.reduce((r, name, i, a) => {
const id = a.slice(0, i + 1).join('/').toLowerCase();
if (!r[name]) {
r[name] = { _: { name, id } };
(r._.children ??= []).push(r[name]._);
}
return r[name];
}, t);
return t;
}, { _: {} })._.children;
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I have following datas,
let response =[
{
"14714733": [
"Android Testing-1",
"Test special manual",
"Test Manual",
"SECESC"
]
},
{
"10110133": [
"Android Testing-1",
"SECESC"
]
}
]
let shipment =[
{
"masterDocumentNumber": "14714733"
},
{
"masterDocumentNumber": "10110133",
}
]
And
let flagIns=[
{
"fieldValue": "SECESC",
"fieldDescription": "Security Escort"
},
{
"fieldValue": "INS",
"fieldDescription": "Inspection"
}
]
How to iterate and add Corresponding response data in to shipment data as follows,
Desired output
let shipment =[
{
"masterDocumentNumber": "14714733",
"instructions":[
{"index":0,"instruction":"Android Testing-1"},
{"index":1,"instruction":"Test special manual"},
{"index":2,"instruction":"Test Manual"},
{"index":3,"instruction":"Security Escort"}
]
},
{
"masterDocumentNumber": "10110133",
"instructions":[
{"index":0,"instruction":"Android Testing-1"},
{"index":1,"instruction":"Security Escort"}
]
}
]
Note that if flagIns has same data in response then it need to be replaced with it's description.
You should be able to use a function similar to this.. it appears you just need to match up keys and values from the different objects..
function aggregate(response, shipment, flagIns) {
return shipment.map(({ masterDocumentNumber }) => {
let output = { masterDocumentNumber, instructions: [] }
let res = response.find(r => masterDocumentNumber in r);
if (res) {
res[masterDocumentNumber].forEach((r, i) => {
let ins = flagIns.find(fi => fi.fieldValue === r);
output.instructions.push({
index: i,
instruction: ins ? ins.fieldDescription : r
})
})
}
return output;
});
}
const response = [
{
"14714733": [
"Android Testing-1",
"Test special manual",
"Test Manual",
"SECESC"
]
},
{
"10110133": ["Android Testing-1", "SECESC"]
}
];
const shipment = [
{
masterDocumentNumber: "14714733"
},
{
masterDocumentNumber: "10110133"
}
];
const flagIns = [
{
fieldValue: "SECESC",
fieldDescription: "Security Escort"
},
{
fieldValue: "INS",
fieldDescription: "Inspection"
}
];
console.log(aggregate(response, shipment, flagIns));
let shipment =[];
//create array
response.map((res)=>{
//get keys
let key=Object.keys(res)
//loop in instructions
let instructions=[];
res[key].map((val,i)=>{
let inst ={
"index":i,
"instruction":val
}
instructions.push(inst)
})
let m={
"masterDocumentNumber":key,
"instructions":instructions
}
shipment.push(m)
})
console.log(JSON.stringify(shipment))
First flatten the response and flagIns array of objects and then iterate over the shipment array to get the desired output.
let response =[
{
"14714733": [
"Android Testing-1",
"Test special manual",
"Test Manual",
"SECESC"
]
},
{
"10110133": [
"Android Testing-1",
"SECESC"
]
}
]
let shipment =[
{
"masterDocumentNumber": "14714733"
},
{
"masterDocumentNumber": "10110133",
}
]
let flagIns=[
{
"fieldValue": "SECESC",
"fieldDescription": "Security Escort"
},
{
"fieldValue": "INS",
"fieldDescription": "Inspection"
}
]
const responseRes = response.reduce(function (acc, item) {
return Object.assign(acc, item);
}, {});
// responseRes
// {
// '10110133': [ 'Android Testing-1', 'SECESC' ],
// '14714733': [
// 'Android Testing-1',
// 'Test special manual',
// 'Test Manual',
// 'SECESC'
// ]
// }
const flagInsRes = flagIns.reduce(function (acc, item) {
return Object.assign(acc, {
[item.fieldValue]: item.fieldDescription});
}, {});
// flagInsRes
// { SECESC: 'Security Escort', INS: 'Inspection' }
const shipmentRes = shipment.map(obj => {
const temp = {};
temp.masterDocumentNumber = obj.masterDocumentNumber
temp.instructions = responseRes[obj.masterDocumentNumber]
.map((item, index) => {
return {
"index":index,
"instruction":flagInsRes[item] ? flagInsRes[item] : item}
});
return temp;
});
console.log(shipmentRes);
I try to write a function in JavaScript which filter an array by a selected property (an value).
But it works for 2 level only I do not understand what do I missing.
The data I want to filter:
var data = [
{
name: "john_pc",
children: [
{
name: "sabrina_pc",
children: [
{
name: "sabrina_pc"
},
{
name: "john_pc"
}
]
},
{
name: "john_pc"
}
]
},
{
name: "sabrina_pc"
}
]
The childrenFilter funciton :
const childrenFilter = (childrenData, filters) => {
let filteredData = childrenData.filter(item => {
for (var property in filters) {
var optionalValues = filters[property];
var value = item[property];
if (item.children) {
item.children = childrenFilter(item.children, filters);
}
let hasValue = value == optionalValues;
if (hasValue) {
return true;
}
return false;
}
return false;
}, this);
return filteredData;
}
Calling the function:
As you can see the 'childrenFilter' get an object which the key is property in the data and the key is value I want to keep.
let result = childrenFilter(data, {
"name": "a1"
});
console.log(JSON.stringify(result, null, 2))
The wanted result :
[
{
"name": "john_pc",
"children": [
{
"name": "sabrina_pc",
"children": [
{
"name": "john_pc"
}
]
},
{
"name": "john_pc"
}
]
}
]
Your filter function does not take into account whether or not children elements match the pattern, therefore even though some child elements of the object match the pattern, the object itself is being filtered out.
Here is the explanation:
{
name: "a2", // does not match filter {name:'a1} so is removed alongside child objects
children: [ // gets removed with parent object
{
name: "a2"
},
{
name: "a1"
}
]
}
This should produce the desired output:
const childrenFilter = (childrenData, filters) => {
let filteredData = childrenData.filter(item => {
for (var property in filters) {
var optionalValues = filters[property];
var value = item[property];
if (item.children) {
item.children = childrenFilter(item.children, filters);
}
let hasValue = value == optionalValues;
if (hasValue || item.children.length) { // include item when children mathes the pattern
return true;
}
return false;
}
return false;
}, this);
return filteredData;
}
You could build new array for each step of filtering, beginning from the leaves and check if this contains the wanted value.
This approach generates new objects and does not mutate the original data.
function filter(array, filters) {
return array.reduce((r, o) => {
var children = filter(o.children || [], filters);
return children || Object.entries(filters).every(([k, v]) => o[k] === v)
? (r || []).concat(Object.assign({}, o, children && { children }))
: r;
}, undefined);
}
var data = [{ name: "a1", children: [{ name: "a2", children: [{ name: "a2" }, { name: "a1" }] }, { name: "a1" }] }, { name: "b1" }];
console.log(filter(data, { name: "a1" }));
.as-console-wrapper { max-height: 100% !important; top: 0; }
So I've been struggling to wrap my head around this recursive function and get the right results.
const _ = require('lodash');
let config = {
"Main": {
children: {
"Dashboard": "main.dashboard",
"Account": {
children: {
"Settings": "main.account.settings"
}
}
}
},
"Statistics": {
children: {
"Test One": "main.statistics.test.one",
"Test Two": "main.statistics.test.two"
}
}
}
let processNav = (config, parent) => {
let children;
let results = {};
_.forOwn(config, (value, title) => {
var breadcrumb = parent || title;
if (value.children) {
children = processNav(value.children, breadcrumb);
_.assign(results, children);
} else {
results[value] = [breadcrumb, title];
}
});
return results;
};
let breadcrumbs = processNav(config);
console.log(breadcrumbs);
// output
{ 'main.dashboard': [ 'Main', 'Dashboard' ],
'main.account.settings': [ 'Main', 'Settings' ],
'main.statistics.test.two': [ 'Statistics', 'Test Two' ] }
The output I'm looking for is more like this...
// expected output
{ 'main.dashboard': [ 'Main', 'Dashboard' ],
'main.account.settings': [ 'Main', 'Account', 'Settings' ],
'main.statistics.test.one': [ 'Statistics', 'Test One' ],
'main.statistics.test.two': [ 'Statistics', 'Test Two' ] }
Can anyone help me wrap my head around this before I go crazy?
This approach doesn't use .lodash, just plain JS.
let config = { "Main": { children: { "Dashboard": "main.dashboard", "Account": { children: { "Settings": "main.account.settings" } } } }, "Statistics": { children: { "Test One": "main.statistics.test.one", "Test Two": "main.statistics.test.two" } }};
function loop(obj, path, breadcrumbs) {
Object.keys(obj).forEach(k => {
if (obj[k].children) loop(obj[k].children, [...path, k], breadcrumbs);
else breadcrumbs[obj[k]] = [...path, k];
});
}
let breadcrumbs = {};
loop(config, [], breadcrumbs);
console.log(JSON.stringify(breadcrumbs, null, 2));
.as-console-wrapper { max-height: 100% !important; top: 0; }
The main difficulty is skipping the children object. Therefore, I included an additional case in the recursive pattern.
If the current "node" has a children property, it "skips" it by immedeately calling the next recursion:
isParent(obj) ? getPaths(obj.children, path, result) : /* ... * /
In action:
const config={Main:{children:{Dashboard:"main.dashboard",Account:{children:{Settings:"main.account.settings"}}}},Statistics:{children:{"Test One":"main.statistics.test.one","Test Two":"main.statistics.test.two"}}};
const isParent = x => x.children;
const isLeaf = x => typeof x === "string";
const getPaths = (obj, path = [], result = {}) =>
isParent(obj)
// The "Skip" case:
? getPaths(obj.children, path, result)
: isLeaf(obj)
// The *final* case:
? Object.assign(result, { [obj]: path })
// The *recurse* case:
: Object.keys(obj).reduce(
(r, k) => getPaths(obj[k], path.concat(k), r),
result);
console.log(getPaths(config));