I have below object which I am currently looping through to get item value. Currently I am using lodash _.forEach to achieve this. I am not sure what is best possible to create a new object with item name as key and value as value.
data = [
{
"panels" : [
{
"title": "Panel 1",
"items" : [
{
"name": item1,
"value": 1
}
{
"name": item2,
"value": 2
}
]
},
{
"title": "Panel 2",
"items" : [
{
"name": item3,
"value": 3
}
{
"name": item4,
"value": 5
}
]
}
]
}
{
"panels" : [
{
"title": "Panel 3"
"items" : [
{
"name": item5,
"value": 5
}
{
"name": item6,
"value": 6
}
]
}
]
}
]
let values = [];
_.forEach(data, (groups) => {
_.forEach(groups.panels, (panel) => {
_.forEach(panel.items, (item) => {
values[item.name] = item.value;
});
});
});
return values;
Is there any other way I can achieve this in more efficient way ?
You could use a nested for...of loops with destructuring
const data=[{panels:[{title:"Panel 1",items:[{name:"item1",value:1},{name:"item2",value:2}]},{title:"Panel 2",items:[{name:"item3",value:3},{name:"item4",value:5}]}]},{panels:[{title:"Panel 3",items:[{name:"item5",value:5},{name:"item6",value:6}]}]}];
const output = {};
for (const { panels } of data)
for (const { items } of panels)
for (const { name, value } of items)
output[name] = value;
console.log(output)
Or,
You could use a chained flatMap to get an array of items. Then reduce the items array to get an object with name as key and value as it's value
const data=[{panels:[{title:"Panel 1",items:[{name:"item1",value:1},{name:"item2",value:2}]},{title:"Panel 2",items:[{name:"item3",value:3},{name:"item4",value:5}]}]},{panels:[{title:"Panel 3",items:[{name:"item5",value:5},{name:"item6",value:6}]}]}];
const output = data.flatMap(o => o.panels)
.flatMap(p => p.items)
.reduce((acc, o) => ({ ...acc, [o.name]: o.value }), {})
console.log(output)
Related
I want to create a nested filter in js
when I filter my array primary data is affected and changed but I need preliminary data to remove filters
my js code :
let result = companies;
result.map((item, i) => {212
let rows = [...result[i].table.table_rows].filter((item3) => {
return Object.keys(item3).some(i => item3[i][key] === value[key]);
});
result[i].table.table_rows = [...rows];
return result[i];
});
arrayFilter(result);
my data is:
{
"companies": [
{
"company": {
"name": "company 1"
},
"table": {
"table_rows": [
{
"cells": {
"product_name": "prod1",
"pa_size": "12"
}
},
{
"cells": {
"product_name": "prod2",
"pa_size": "15"
}
}
]
}
},
{
"company": {
"name": "company 2"
},
"table": {
"table_rows": [
{
"cells": {
"product_name": "prod2-1",
"pa_size": "12"
}
},
{
"cells": {
"product_name": "prod2-2",
"pa_size": "18"
}
}
]
}
}
]
}
I tried many ways to solve this problem, but I did not get the right answer
Your question is not clear, the point I have understand that you wanted to filter the array "table_rows" located inside each companies array object? map and filter returns new array, so the solution for this is:
result = result.companies.map((item, i) => {
const newItem = {...item};
let rows = newItem .table.table_rows.filter((item3) => {
return Object.keys(item3).some(i => item3[i][key] === value[key]);
});
newItem.table_rows = [...rows];
return newItem ;
});
arrayFilter(result);
I have below object which I am currently looping through in number of different functions to get an item with name or setting a new value. Currently I am using lodash _.foreach and ._map to achieve both actions. I know lodash has function such as _.filter however I am unable to get it to work with the object that I have.
let data = [
{
"panels" : [
{
"title": "Panel 1",
"items" : [
{
"name": item1,
"value": 1
}
{
"name": item2,
"value": 2
}
]
},
{
"title": "Panel 2",
"items" : [
{
"name": item3,
"value": 3
}
{
"name": item4,
"value": 5
}
]
}
]
}
{
"panels" : [
{
"title": "Panel 3"
"items" : [
{
"name": item5,
"value": 5
}
{
"name": item6,
"value": 6
}
]
}
]
}
{
"panels" : [
{
"title": "Panel 4"
"items" : [
{
"name": item7,
"value": 7
}
{
"name": item8,
"value": 8
}
]
}
]
}
]
// Get item from the object with given name
getItem: function(name) {
let item = false;
_.forEach(data, function (group) {
_.forEach(group.panels, function (panel) {
_.forEach(panel.items, function (item) {
if (item.name == name) {
filterItem = item;
return false;
}
});
});
});
return item ;
},
//Set item new value
updateItemValue (name, value) {
_.map(data, function(group) {
_.map(group.panels, function(panel) {
_.map(panel.items, function(item) {
if( item.name === name ) {
item.value = value;
}
});
});
});
}
Is there any other way I can achieve this in more efficient way ?
You could use nested for...of loops with destructuring. If an item has the provided name, return the item. Apply the same approach to updateItemValue as well
const data=[{panels:[{title:"Panel 1",items:[{name:"item1",value:1},{name:"item2",value:2}]},{title:"Panel 2",items:[{name:"item3",value:3},{name:"item4",value:4}]}]},{panels:[{title:"Panel 3",items:[{name:"item5",value:5},{name:"item6",value:6}]}]}];
function getItem(name) {
for (const { panels } of data)
for (const { items } of panels)
for (const o of items)
if (o.name === name)
return o
return; // if no match is found
}
function updateItemValue(name, value) {
for (const { panels } of data)
for (const { items } of panels)
for (const o of items)
if (o.name === name) {
o.value = value
return;
}
}
console.log(getItem('item1'))
console.log(getItem('item2'))
console.log(getItem('doesntexist'))
updateItemValue('item3', 33) // update the value
console.log(getItem('item3')) // gets the updated value
I have this nested object (json):
const json = {
"application": {
"App1": {
"cats": [
1
]
},
"App2": {
"cats": [
3
]
},
"App3": {
"cats": [
1,
2
]
}
},
"categories": {
"1": {
"name": "FirstCategory"
},
"2": {
"name": "SecondCategory"
},
"3": {
"name": "ThirdCategory"
}
}
};
This object has two main properties: application and categories.
I want to map over application's cats array and get name property of each element of cats array.
So the final result should look like:
{
"App1": "FirstCategory",
"App2": "ThirdCategory",
"App3": "FirstCategory, ThirdCategory"
}
I have tried to use map function, but the main difficulty is that inside applicaiton property cats is array (can have multiple values). So the code below didn't work:
Object.values(json.application).map(val => {
Object.keys(json.categories).map(key => {
//print something
});
});
You can use Array.reduce for an elegant solution.
const json = {
"application": {
"App1": {
"cats": [
1
]
},
"App2": {
"cats": [
3
]
},
"App3": {
"cats": [
1,
2
]
}
},
"categories": {
"1": {
"name": "FirstCategory"
},
"2": {
"name": "SecondCategory"
},
"3": {
"name": "ThirdCategory"
}
}
};
//Getting Application object
const application = json.application
//Getting Categories object
const categories = json.categories
//initializing reduce with a blank object and pushing all the keys of the application object
//Looping over keys of application object
const requiredOutput = Object.keys(application).reduce((out, appKey) => {
//Setting value based on categories name
out[appKey] = application[appKey].cats.map(id => categories[id].name)
return out
}, {})
console.log(requiredOutput)
PS: You can refer this gist for safe reading from a nested object.
Try it with this.
for(let val in json.application){
json.application[val] = json.application[val].cats.map(cat => json.categories[cat].name).join(",")
}
const result = Object.keys(json.application).reduce((a,key) => {
a[key] = json.application[key].cats
.map(cat => json.categories[cat].name)
.join(", ")
return a;
}, {})
loop over keys of application
for each key loop over car, and for each cat return string value from category
join list of cat strings
I am currently with some JSON, which has to be structured in a tree-like hierarchy. The depth of the hierarchy varies a lot, and is therefor unknown.
As it is right now, I have achieved to get an array of objects. Example is below.
[
{
"name": "level1",
"collapsed": true,
"children": [
{
"name": "Level 1 item here",
"id": 360082134191
}
]
},
{
"name": "level1",
"collapsed": true,
"children": [
{
"name": "level2",
"collapsed": true,
"children": [
{
"name": "Level 2 item here",
"id": 360082134751
}
]
}
]
},
{
"name": "level1",
"collapsed": true,
"children": [
{
"name": "Another level 1 item",
"id": 360082262772
}
]
}
]
What I want to achieve is these objects to be merged, without overwriting or replacing anything. Listed below is an example of how I want the data formatted:
[
{
"name": "level1",
"collapsed": true,
"children": [
{
"name": "level2",
"collapsed": true,
"children": [
{
"name": "Level 2 item here",
"id": 360082134751
}
]
},
{
"name": "Level 1 item here",
"id": 360082134191
},
{
"name": "Another level 1 item",
"id": 360082262772
}
]
}
]
How would I achieve this with JavaScript? No libraries is preferred, ES6 can be used though.
Edit:
It is important that the output is an array, since items without children can appear at the root.
I am assuming you need a little help on working with the data. There could be multiple ways to achieve this, here is how would I do.
// data => supplied data
const result = data.reduce ((acc, item) => {
// if acc array already contains an object with same name,
// as current element [item], merfe the children
let existingItem;
// Using a for loop here to create a reference to the
// existing item, so it'd update this item when childrens
// will be merged.
for (let index = 0; index < acc.length; index ++) {
if (acc[index].name === item.name) {
existingItem = acc[index];
break;
}
}
// if existingItem exists, merge children of
// existing item and current item.
// else push it into the accumulator
if (existingItem) {
existingItem.children = existingItem.children.concat(item.children);
} else {
acc.push (item);
}
return acc;
}, []);
I'm assuming you want to group based on the name property in the level 1 object. You could do a simple reduce and Object.values like this:
const input = [{"name":"level1","collapsed":true,"children":[{"name":"Level 1 item here","id":360082134191}]},{"name":"level1","collapsed":true,"children":[{"name":"level2","collapsed":true,"children":[{"name":"Level 2 item here","id":360082134751}]}]},{"name":"level1","collapsed":true,"children":[{"name":"Another level 1 item","id":360082262772}]}]
const merged = input.reduce((r,{name, collapsed, children}) =>{
r[name] = r[name] || {name, collapsed, children:[]};
r[name]["children"].push(...children)
return r;
}, {})
const final = Object.values(merged);
console.log(final)
You could do the whole thing in one line:
const input = [{"name":"level1","collapsed":true,"children":[{"name":"Level 1 item here","id":360082134191}]},{"name":"level1","collapsed":true,"children":[{"name":"level2","collapsed":true,"children":[{"name":"Level 2 item here","id":360082134751}]}]},{"name":"level1","collapsed":true,"children":[{"name":"Another level 1 item","id":360082262772}]}]
const output = Object.values(input.reduce((r,{name,collapsed,children}) => (
(r[name] = r[name] || {name,collapsed,children: []})["children"].push(...children), r), {}))
console.log(output)
I have a json getting from API and store it into this.state.data like :
[
{
"name": "Primary Category",
"value": [
{
"value": "Fracture",
"Diagnosis_Code": ["DIAG003"],
"name": "Primary Category",
"FK_Diagnosis_Content_ID": 3,
"FK_Diagnosis_Category_ID": 1
},
{
"value": "Osteoarthritis",
"Diagnosis_Code": ["DIAG001"],
"name": "Primary Category",
"FK_Diagnosis_Content_ID": 1,
"FK_Diagnosis_Category_ID": 1
},
{
"value": "Osteonecrosis",
"Diagnosis_Code": ["DIAG002", "DIAG004"],
"name": "Primary Category",
"FK_Diagnosis_Content_ID": 2,
"FK_Diagnosis_Category_ID": 1
},
]
},
{
"name": "Anatomy",
"value": [
{
"value": "Hip",
"Diagnosis_Code": ["DIAG001"],
"name": "Anatomy",
"FK_Diagnosis_Content_ID": 4,
"FK_Diagnosis_Category_ID": 2
},
{
"value": "Pelvis",
"Diagnosis_Code": ["DIAG002", "DIAG003", "DIAG004"],
"name": "Anatomy",
"FK_Diagnosis_Content_ID": 6,
"FK_Diagnosis_Category_ID": 2
}
]
}
]
and I have a dynamic state using a function like this:
onChangeTextPress(key, value){
this.state.selected[key] = value
//another code
}
the example of this.state.selected is
[ 'Primary Category': 'Fracture', Anatomy: 'Hip']
I want to get FK_Diagnosis_Content_ID json depending on which this.state.selected[key] and it's value filled
so depending of selected example, I will have a result: [3, 4]
because json have a key called name and the value is Primary Category, and the value of selected state Primary Category is Fracture so I have a value of FK_Diagnosis_Content_ID in json, likewise about the Anatomy: 'Hip'
I don't know if you all know what I want, but feel free to asking me if you need another information,
hope someone can help me
You can get use of Object.keys() and Array.prototype.includes().
Sample 1
// Let's assume you have the below structure
const data = { 'Primary Category': 'Fracture', Anatomy: 'Hip' }
Object.keys(data).forEach((key) => console.log(key))
// Output:
// Primary Category
// Anatomy
So to get the desired value you can use something like below
Sample 2
// this.state.selected => { 'Primary Category': 'Fracture', Anatomy: 'Hip' }
const keys = Object.keys(this.state.selected);
const result = [];
this.state.data.forEach((d) => {
if(keys.includes(d.name)) {
d.value.forEach((v) => {
if(v.value === this.state.selected[d.name]) {
result.push(v['FK_Diagnosis_Content_ID']);
}
})
}
});
console.log(result);
// Output: [3,4]
Sample 3
// this.state.selected => [{ 'Primary Category': 'Fracture'}, {Anatomy: 'Hip' }]
// Since we know there is only one key in every object
const keys = this.state.selected.map((s) => Object.keys(s)[0])
const result = [];
this.state.data.forEach((d) => {
if(keys.includes(d.name)) {
d.value.forEach((v) => {
if(v.value === this.state.selected[keys.indexOf(d.name)][d.name]) {
result.push(v['FK_Diagnosis_Content_ID']);
}
})
}
});
console.log(result);
// Output: [3,4]
You can use this just as
const key = Object.keys(this.state.selected);
const response = [];
this.state.data.forEach((d) => {
if(key.includes(d.tag)) {
d.value.forEach((v) => {
if(v.value === this.state.selected[d.name]) {
result.push(v['FK_Diagnosis_Content_ID']);
}
})
}
});
console.log(result);