I need to calculate a score based on departments in groups. To simplify that I used only 1 group as an example.
I'm receiving this data structure:
const data = [{
"id": "cklt7ln1k0922o0sabjkk74m9",
"score": 80,
"count": 1,
"department": "Engineering",
"group": "Group one"
},
{
"id": "cklt7ln1k0922o0sabjkk74m9",
"score": 40,
"count": 1,
"department": "Executive",
"group": "Group one"
},
{
"id": "cklt7ln1k0922o0sabjkk74m9",
"score": 40,
"count": 1,
"department": "OOO Boost",
"group": "Group one"
},
{
"id": "cklt7ln1k0922o0sabjkk74m9",
"score": 60,
"count": 1,
"department": "Engineering",
"group": "Group one"
},
{
"id": "cklt7ln1k0922o0sabjkk74m9",
"score": 100,
"count": 2,
"department": "Supporting Department",
"group": "Group one"
},
{
"id": "cklt7ln1k0922o0sabjkk74m9",
"score": 20,
"count": 1,
"department": "Designers",
"group": "Group one"
},
{
"id": "cklt7ln1k0922o0sabjkk74m9",
"score": 20,
"count": 1,
"department": "Executive",
"group": "Group one"
}
];
and I need to create a data structure for a heatmap:
const heatmapData = [
{
row: 'Group one',
columns: [
{
name: 'Engineering',
averageScore: 70, // (80[score] * 1[count] + 60[score] * 1[count]) / 2[sum of count -> 1+1]
},
{
name: 'Supporting Department',
averageScore: 100, // 100[score] * 2[count] / 2[sum of count -> 2]
},
.... next unique departments
]
}
]
I'm a bit stacked with some simple solution of grouping data with calculation. Could you help me please? Thank you
You can group your data based on the group and for each group, group it on department and sum up score and count. Once you have this object, you can calculate average for each department.
const data = [{ "id": "cklt7ln1k0922o0sabjkk74m9", "score": 80, "count": 1, "department": "Engineering", "group": "Group one" }, { "id": "cklt7ln1k0922o0sabjkk74m9", "score": 40, "count": 1, "department": "Executive", "group": "Group one" }, { "id": "cklt7ln1k0922o0sabjkk74m9", "score": 40, "count": 1, "department": "OOO Boost", "group": "Group one" }, { "id": "cklt7ln1k0922o0sabjkk74m9", "score": 60, "count": 1, "department": "Engineering", "group": "Group one" }, { "id": "cklt7ln1k0922o0sabjkk74m9", "score": 100, "count": 2, "department": "Supporting Department", "group": "Group one" }, { "id": "cklt7ln1k0922o0sabjkk74m9", "score": 20, "count": 1, "department": "Designers", "group": "Group one" }, { "id": "cklt7ln1k0922o0sabjkk74m9", "score": 20, "count": 1, "department": "Executive", "group": "Group one" } ],
grouped = data.reduce((r, {group, department, score, count}) => {
r[group] = r[group] || {};
r[group][department] = r[group][department] || {department, totalScore: 0, count: 0 };
r[group][department].totalScore += score * count;
r[group][department].count += count;
return r;
},{}),
result = Object.keys(grouped).map(k => {
const columns = Object.values(grouped[k]).map(d => ({
department: d.department,
averageScore: d.totalScore/d.count
}));
return {row: k, columns };
})
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can group items into the dictionary:
let group = data.reduce((acc, val) => {
if(!acc[val.group]) acc[val.group] = {};
if(!acc[val.group][val.department]) acc[val.group][val.department] = {sum:0, count: 0, averageScore: 0};
acc[val.group][val.department] = {
sum: acc[val.group][val.department].sum+val.score,
count: acc[val.group][val.department].count + 1,
averageScore: (acc[val.group][val.department].sum+val.score) / (acc[val.group][val.department].count + 1)
}
return acc
}, {});
then map it to requested format:
Object.keys(group).map(row => {
return {
row: row,
columns: Object.keys(group[row]).map(col => {return {name: col, averageScore: group[row][col].averageScore}})
}
})
Allow me to explain how it works.. so we know that objects are pointers more than they are values.. I used that principle throughout the solution. I have the array to return(where I push stuff), then I had 2 Objects to store values(and editing those Objects edited the "values" in the array), so in the array you pass in, I basically add values to these objects and link them in the array(the format you desire)
UPDATED AGAIN.. I applied the logic of your calculation examples >:D
function group(array){
let arr=[]; let groups={}; let departments={}
array.forEach(a=>{
if(!groups[a.group]){ //setting each group
groups[a.group]={row:a.group,columns:[]}
arr.push(groups[a.group])
}
if(!departments[a.department]){ //setting each department
departments[a.department]=[{name:a.department,averageScore:a.score*a.count},a.count] //score * count and count(because of your calculation examples)
groups[a.group].columns.push(departments[a.department][0])
}
else{ //adding department when they already exist
departments[a.department][1]+=a.count //count
departments[a.department][0].averageScore+=a.score*a.count //score * count
//(because of your calculation examples)
}
})
Object.keys(departments).forEach(a=>departments[a][0].averageScore/=departments[a][1])
return arr
}
console.log(group(data))
<script>
//to not take out unnecesary space in the answer
window.data = [{
"id": "cklt7ln1k0922o0sabjkk74m9",
"score": 80,
"count": 1,
"department": "Engineering",
"group": "Group one"
},
{
"id": "cklt7ln1k0922o0sabjkk74m9",
"score": 40,
"count": 1,
"department": "Executive",
"group": "Group one"
},
{
"id": "cklt7ln1k0922o0sabjkk74m9",
"score": 40,
"count": 1,
"department": "OOO Boost",
"group": "Group one"
},
{
"id": "cklt7ln1k0922o0sabjkk74m9",
"score": 60,
"count": 1,
"department": "Engineering",
"group": "Group one"
},
{
"id": "cklt7ln1k0922o0sabjkk74m9",
"score": 100,
"count": 2,
"department": "Supporting Department",
"group": "Group one"
},
{
"id": "cklt7ln1k0922o0sabjkk74m9",
"score": 20,
"count": 1,
"department": "Designers",
"group": "Group one"
},
{
"id": "cklt7ln1k0922o0sabjkk74m9",
"score": 20,
"count": 1,
"department": "Executive",
"group": "Group one"
}
];
</script>
Related
I have an array like this:
Array [
Object {
"item": Object {
"amount": 1,
"price": 29.99,
"product_id": 5,
"product_name": "Calvin klein Bag",
"username": "Ester71",
},
"type": "NORMAL",
},
Object {
"item": Object {
"amount": 1,
"price": 29.99,
"product_id": 3,
"product_name": "Calvin klein Bag",
"username": "Ester71",
},
"type": "NORMAL",
},
Object {
"item": Object {
"amount": 1,
"price": 29.99,
"product_id": 5,
"product_name": "Calvin klein Bag",
"username": "Ester71",
},
"type": "NORMAL",
},
],
I want groupby product_id. But it doesnt work.
Here is an example with colors. It works, and if I remove the item in the above array then it also works, but the item have to do there.
var data = [{
"name": "jim",
"color": "blue",
"age": "22"
}, {
"name": "Sam",
"color": "blue",
"age": "33"
}, {
"name": "eddie",
"color": "green",
"age": "77"
}];
console.log(
_.chain(data)
// Group the elements of Array based on `color` property
.groupBy("color")
// `key` is group's name (color), `value` is the array of objects
.map((value, key) => ({ color: key, users: value }))
.value()
);
So how can I now groupby item.product_id ?
You can try this
const data = [
{
"item": {
"amount": 1,
"price": 29.99,
"product_id": 5,
"product_name": "Calvin klein Bag",
"username": "Ester71",
},
"type": "NORMAL",
},
{
"item": {
"amount": 1,
"price": 29.99,
"product_id": 3,
"product_name": "Calvin klein Bag",
"username": "Ester71",
},
"type": "NORMAL",
},
{
"item": {
"amount": 1,
"price": 29.99,
"product_id": 5,
"product_name": "Calvin klein Bag",
"username": "Ester71",
},
"type": "NORMAL",
},
]
const groupBy = (product) => product.item.product_id
console.log(
_.chain(data)
.groupBy(groupBy)
.map((value, key) => ({ product_id: key, products: value }))
.value()
);
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.21/lodash.min.js"></script>
I need to convert below unformatted JSON format into formatted input. We need to find id's similar to parent id for different items inside array element of object and then need to push it into children to that id. Below is my code that needs to transform
Input
{
"0": [
{
"id": 10,
"title": "House",
"level": 0,
"children": [],
"parent_id": null
}
],
"1": [
{
"id": 12,
"title": "Red Roof",
"level": 1,
"children": [],
"parent_id": 10
},
{
"id": 18,
"title": "Blue Roof",
"level": 1,
"children": [],
"parent_id": 10
}
],
"2": [
{
"id": 17,
"title": "Blue Windoww",
"level": 2,
"children": [],
"parent_id": 12
},
{
"id": 16,
"title": "Door",
"level": 2,
"children": [],
"parent_id": 13
}
]
}
Output
[
{
"id": 10,
"title": "House",
"level": 0,
"children": [
{
"id": 12,
"title": "RedRoofff",
"level": 1,
"children": [
{
"id": 17,
"title": "Blue Windoww",
"level": 2,
"children": [],
"parent_id": 12
}
],
"parent_id": 10
},
{
"id": 18,
"title": "Blue Roof",
"level": 1,
"children": [],
"parent_id": 10
},
{
"id": 13,
"title": "Wall",
"level": 1,
"children": [
{
"id": 16,
"title": "Door",
"level": 2,
"children": [],
"parent_id": 13
}
],
"parent_id": 10
}
],
"parent_id": null
}
]
Please find the solution to above problem.
first, we track the node with Id and then we update the children array like this.
(btw, your input have a missing node, 13)
const input = {
"0": [{
"id": 10,
"title": "House",
"level": 0,
"children": [],
"parent_id": null
}, {
"id": 13,
"title": "Wall",
"level": 0,
"children": [],
"parent_id": null
}],
"1": [{
"id": 12,
"title": "Red Roof",
"level": 1,
"children": [],
"parent_id": 10
},
{
"id": 18,
"title": "Blue Roof",
"level": 1,
"children": [],
"parent_id": 10
},
],
"2": [{
"id": 17,
"title": "Blue Windoww",
"level": 2,
"children": [],
"parent_id": 12
},
{
"id": 16,
"title": "Door",
"level": 2,
"children": [],
"parent_id": 13
},
]
};
const results = [];
const mapId2Node = Object.values(input).reduce((acc, vals) => {
vals.forEach(val => {
acc[val.id] = val;
if (val.parent_id === null) {
results.push(val);
}
});
return acc;
}, {});
Object.values(input).forEach(vals => {
vals.forEach(val => {
if (val.parent_id !== null) {
mapId2Node[val.parent_id].children.push(val);
}
});
});
conosle.log(results);
I am trying to get specific object from a whole object below is the example
by using localStorage.getItem('shop/elasticCache/shirt');
I get below data
{"description":"Tech Shirt","configurable_options":[{"attribute_id":80,"values":[{"value_index":"5176","label":"RUST"}],"label":"Color","attribute_code":"color"},{"attribute_id":125,"values":[{"value_index":"2898","label":"Small"},{"value_index":"2901","label":"Medium"},{"value_index":"2904","label":"Large"}],"label":"Size","attribute_code":"size"}],"tsk":1594790209,"size_options":[2898,2901,2904],"regular_price":28,"final_price":null,"price":28,"color_options":[5176],"special_from_date":null,"id":250659,"category":[{"category_id":2,"name":"Default Category","position":1},{"category_id":3,"name":"Clothing","position":14985},{"category_id":30,"name":"Bottoms","position":798},{"category_id":58,"name":"Leggings","position":1},{"category_id":1130,"name":"Char Test Category","position":30}],"sku":"S155551","product_links":[{"link_type":"related","linked_product_sku":null,"linked_product_type":null,"position":0,"sku":"P100031"},{"link_type":"related","linked_product_sku":null,"linked_product_type":null,"position":0,"sku":"P100031"}
I am trying to get
{"category_id":3,"name":"Clothing","position":14985},{"category_id":30,"name":"Bottoms","position":798},{"category_id":58,"name":"Leggings","position":1},{"category_id":1130,"name":"Char Test Category","position":30}]
Is their any way it can be done ?
const {category} = JSON.parse(localStorage.getItem('shop/elasticCache/shirt');)
or
const {category } = {
"description": "Tech Shirt",
"configurable_options": [{
"attribute_id": 80,
"values": [{
"value_index": "5176",
"label": "RUST"
}],
"label": "Color",
"attribute_code": "color"
}, {
"attribute_id": 125,
"values": [{
"value_index": "2898",
"label": "Small"
}, {
"value_index": "2901",
"label": "Medium"
}, {
"value_index": "2904",
"label": "Large"
}],
"label": "Size",
"attribute_code": "size"
}],
"tsk": 1594790209,
"size_options": [2898, 2901, 2904],
"regular_price": 28,
"final_price": null,
"price": 28,
"color_options": [5176],
"special_from_date": null,
"id": 250659,
"category": [{
"category_id": 2,
"name": "Default Category",
"position": 1
}, {
"category_id": 3,
"name": "Clothing",
"position": 14985
}, {
"category_id": 30,
"name": "Bottoms",
"position": 798
}, {
"category_id": 58,
"name": "Leggings",
"position": 1
}, {
"category_id": 1130,
"name": "Char Test Category",
"position": 30
}],
"sku": "S155551",
"product_links": [{
"link_type": "related",
"linked_product_sku": null,
"linked_product_type": null,
"position": 0,
"sku": "P100031"
}, {
"link_type": "related",
"linked_product_sku": null,
"linked_product_type": null,
"position": 0,
"sku": "P100031"
}]
}
objc={"description":"Tech Shirt","configurable_options":
[{"attribute_id":80,"values":[{"value_index":"5176","label":"RUST"}],
"label":"Color","attribute_code":"color"},
{"attribute_id":125,"values":[{"value_index":"2898","label":"Small"}
,{"value_index":"2901","label":"Medium"},
{"value_index":"2904","label":"Large"}],
"label":"Size","attribute_code":"size"}],
"tsk":1594790209,"size_options":[2898,2901,2904]
,"regular_price":28,"final_price":null,"price":28,
"color_options":[5176],"special_from_date":null,"id":250659,
"category":[{"category_id":2,"name":"Default Category","position":1},
{"category_id":3,"name":"Clothing","position":14985},
{"category_id":30,"name":"Bottoms","position":798},
{"category_id":58,"name":"Leggings","position":1},
{"category_id":1130,"name":"Char Test Category","position":30}],
"sku":"S155551","product_links":
[{"link_type":"related","linked_product_sku":null,"linked_product_type":null,"position":0,"sku":"P100031"},
{"link_type":"related","linked_product_sku":null,"linked_product_type":null,"position":0,"sku":"P100031"}]
}
res = objc["category"]
res.shift()
console.log(res)
$(document).ready(function () {
var jsonObj = {
"description": "Tech Shirt",
"configurable_options": [{
"attribute_id": 80,
"values": [{
"value_index": "5176",
"label": "RUST"
}],
"label": "Color",
"attribute_code": "color"
}, {
"attribute_id": 125,
"values": [{
"value_index": "2898",
"label": "Small"
}, {
"value_index": "2901",
"label": "Medium"
}, {
"value_index": "2904",
"label": "Large"
}],
"label": "Size",
"attribute_code": "size"
}],
"tsk": 1594790209,
"size_options": [2898, 2901, 2904],
"regular_price": 28,
"final_price": null,
"price": 28,
"color_options": [5176],
"special_from_date": null,
"id": 250659,
"category": [{
"category_id": 2,
"name": "Default Category",
"position": 1
}, {
"category_id": 3,
"name": "Clothing",
"position": 14985
}, {
"category_id": 30,
"name": "Bottoms",
"position": 798
}, {
"category_id": 58,
"name": "Leggings",
"position": 1
}, {
"category_id": 1130,
"name": "Char Test Category",
"position": 30
}],
"sku": "S155551",
"product_links": [{
"link_type": "related",
"linked_product_sku": null,
"linked_product_type": null,
"position": 0,
"sku": "P100031"
}, {
"link_type": "related",
"linked_product_sku": null,
"linked_product_type": null,
"position": 0,
"sku": "P100031"
}]
};
for(var i = 1; i < jsonObj.category.length; i++){
console.log(jsonObj.category[i]);
}
});
You can iterate through the entire object and can get the required values. The above code gives the values of category from index 1.
I have a json file which contains the list of products.
[{"id":76,
"name":"A",
"description":"abc",
"price":199,
"imageUrl":"image.jpg",
"productCategory":[{
"categoryId":5,
"category":null
},{
"categoryId":6,
"category":null
}
]}
I then have a second json file with a list of categories which look like so:
[{"id":5,"name":"red"},
{"id":6,"name”:"blue"}]
What is the best way to join the categories of this two json files in Angular?
This is what I aim to achieve:
[{"id":76,
"name":"A",
"description":"abc",
"price":199,
"imageUrl":"image.jpg",
"productCategory":[{
"categoryId":5,
"category":red
},{
"categoryId":6,
"category":blue
}
]}
You can use filter function for your requirement as below
let products = [{
"id": 76,
"name": "A",
"description": "abc",
"price": 199,
"imageUrl": "image.jpg",
"productCategory": [{
"categoryId": 2,
"category": null
}, {
"categoryId": 1,
"category": null
}]
}, {
"id": 77,
"name": "B",
"description": "abcd",
"price": 1997,
"imageUrl": "image.jpg",
"productCategory": [{
"categoryId": 5,
"category": null
}, {
"categoryId": 6,
"category": null
}]
},
{
"id": 78,
"name": "C",
"description": "abcde",
"price": 1993,
"imageUrl": "image.jpg",
"productCategory": [{
"categoryId": 4,
"category": null
}, {
"categoryId": 6,
"category": null
}]
}];
let category = [{ "id": 5, "name": "red" }, { "id": 6, "name": "blue" }]
let result = products.filter(p => {
var exist = p.productCategory.filter(pc => category.find(c => c.id == pc.categoryId))[0];
return exist;
});
console.log(result);
let products = [{
"id": 76,
"name": "A",
"description": "abc",
"price": 199,
"imageUrl": "image.jpg",
"productCategory": [{
"categoryId": 2,
"category": null
}, {
"categoryId": 1,
"category": null
}]
}, {
"id": 77,
"name": "B",
"description": "abcd",
"price": 1997,
"imageUrl": "image.jpg",
"productCategory": [{
"categoryId": 5,
"category": null
}, {
"categoryId": 6,
"category": null
}]
},
{
"id": 78,
"name": "C",
"description": "abcde",
"price": 1993,
"imageUrl": "image.jpg",
"productCategory": [{
"categoryId": 4,
"category": null
}, {
"categoryId": 6,
"category": null
}]
}];
let category = [{ "id": 5, "name": "red" }, { "id": 6, "name": "blue" }]
let result = products.filter(p => {
var exist = p.productCategory.filter(pc => category.find(c => c.id == pc.categoryId))[0];
return exist;
});
console.log(result);
I make a stackblitz that use a service to retreive the data. Yes, the way is using switchMap and map. SwitchMap receive an array and must return an observable. with map, we transform the data received and return the data transformed
this.dataService.getCategories().pipe(
//first get the categories, the categories is in the
//variable cats
switchMap((cats:any[])=>{
return this.dataService.getProducts().pipe(map((res:any[])=>{
res.forEach(p=>{ //with each product
p.productCategory.forEach(c=>{ //with each productCategory in product
//equals a propertie "category" to the propertie "name" of the cats
c.category=cats.find(x=>x.id==c.categoryId).name
})
})
return res
}))
})).subscribe(res=>{
console.log(res)
})
If only has an unique product we can make
this.dataService.getCategories().pipe(
switchMap((cats:any[])=>{
return this.dataService.getUniqProduct(2).pipe(map((res:any)=>{
res.productCategory.forEach(c=>{
c.category=cats.find(x=>x.id==c.categoryId).name
})
return res
}))
})).subscribe(res=>{
console.log(res)
})
We can improve our dataService "cached" the categories
getCategories() {
if (this.categories)
return of(this.categories);
return http.get(......).pipe(tap(res=>{
this.categories=res;
}))
}
NOTE:In the stackbit I simulate the call to an http.get(...) using "of"
const myJSON = {
"seller1": [
{
"product": "headphones",
"price": 23,
"weight": 1
},
{
"product": "earphone",
"price": 12,
"weight": 1
},
{
"product": "iPhone",
"price": 999,
"weight": 3
},
{
"product": "ipad",
"price": 399,
"weight": 4
}
],
"seller2": [
{
"product": "headphones",
"price": 25,
"weight": 1
},
{
"product": "earphone",
"price": 10,
"weight": 1
},
{
"product": "iPhone",
"price": 949,
"weight": 2
},
{
"product": "ipad",
"price": 449,
"weight": 3
}
]
}
I need to filter myJSON from a multi-select box where, if user selects product: iPhone and product: headphones, I need to display all the products that matches iPhone and headphones. In this case, myJSON will be
const myJSON = {
"seller1": [
{
"product": "headphones",
"price": 23,
"weight": 1
},
{
"product": "iPhone",
"price": 999,
"weight": 3
}
],
"seller2": [
{
"product": "headphones",
"price": 25,
"weight": 1
},
{
"product": "iPhone",
"price": 949,
"weight": 2
},
]
}
Now if the user selects different key, price: 449, myJSON should now be empty coz there is not property price: 449 in that anymore. But, if price: 23 then,
const myJSON = {
"seller1": [
{
"product": "headphones",
"price": 23,
"weight": 1
}
]
}
So for example, if user selects 3 items with same key(product), the we should show all the three items that match these 3 items from original json. Now when he selects a different key(price), then we should only filter from the previous result.
Any suggestion on how to implement this is much appreciated.