'Create a computed JSON array in JS with multiple variables
First off, apologies if this is normally a simple thing, but I'm not particularly experienced in JS. I'm trying to make some graphs in Plotly.js for a work site that currently holds raw JSON. We have a JSON in the format:
stuff = [{"name": "shark", "location": "somewhere", "number":10},
{"name": "shark", "location": "somewhereelse", "number":50},
{"name": "shark", "location": "somewhere", "number":25},
{"name": "turtle", "location": "anotherplace", "number":1},
{"name": "elephant", "location": "greatplace", "number":50},
{"name": "elephant", "location": "greatplace", "number":75}
And I need the result to look like:
computed = [{"name":"shark", "location":"somewhere", "number":35},
{"name":"shark", "location":"somewhereelse", "number":50},
{"name":"turtle", "location":"anotherplace", "number":1},
{"name":"elephant", "location":"greatplace", "number":125}
Where all names are grouped by location and all numbers in that group are summed. It is then this computed JSON that I'll be using to graph with Plotly.js with some functions I have already built.
I think I can simplify the problem as:
forEach((item) => {
x.push(item['location']
y.push(y += stuff.number where stuff.location === x[-1])
}
But this also means I'll get the same number of rows as in stuff, just computed and graphed. I'm afraid I can't figure it out any further.
Any help would be muchly appreciated.
Solution 1:[1]
Sorry for not replying to this sooner, and thanks to those who commented. For whatever reason I couldn't get the other suggested solutions to work but I seeing another perspective on the logic needed helped me figure it out.
if (!label.includes(item['specimen'] + ':' + item['well_label'] + ':' + item['run'] + ':' + item['group'])) {
label.push(item['specimen'] + ':' + item['well_label'] + ':' + item['run'] + ':' + item['group'])
x.push(item['date'])
y.push(item['sum'])
} else {
var indx = label.indexOf(item['specimen'] + ':' + item['well_label'] + ':' + item['run'] + ':' + item['group'])
let summed = y[indx] + item['sum']
y.splice(indx, 1, summed)
So essentially this created something akin to a compound key, and pushes the initial data to add it to the label list and then the data to the relevant lists. If that compound key appears again then the value is just updated with the splice method.
Only issue is that because these lists are not linked in anyway than the data being input to them, there is a rare chance of the right label and data not matching up but after a lot of testing I have sorted that out and it does work.
Again thanks to the previous commenters that helped.
Solution 2:[2]
Simply looping out the original array, and adding the elements to a new array unless they are added already, or just adding the number will be the trick here. Here's the defined one:
var computed: any = [];
for(var element of stuff){
let computedElement = computed.find((ele: { location: string; }) => ele.location == element.location);
if (computedElement){
computedElement.number += element.number;
}
else{
computed.push(element);
}
}
Solution 3:[3]
First of all, json starts with {} and not []. Your object is a javascript object. I did a very long function below:
const stuffList = [
{"name": "shark", "location": "somewhere", "number":10},
{"name": "shark", "location": "somewhereelse", "number":50},
{"name": "shark", "location": "somewhere", "number":25},
{"name": "turtle", "location": "anotherplace", "number":1},
{"name": "elephant", "location": "greatplace", "number":50},
{"name": "elephant", "location": "greatplace", "number":75}
]
//extract all available location
const locations = stuffList.map( stuffItem => {
return stuffItem.location
})
const filteredStuff = locations.map( location => {
const number= stuffList.map( stuffItem => {
if(stuffItem.location === location) {
return stuffItem.number
}
return 0
}).reduce( (a, b) => a + b)// total all the numbers of mathcing
location
//get the first newStuffItem value equals to location
const [filteredStuffItem] = stuffList.map( stuffItem => {
if(stuffItem.location === location) {
return {
name: stuffItem.name,
location,
number
}
}
}).filter( stuffItem => {
return stuffItem?.location === location
})
return filteredStuffItem
})
const newStuffList = filteredStuff.filter((thing, index) => {
const _thing = JSON.stringify(thing);
return index === filteredStuff.findIndex(obj => {
return JSON.stringify(obj) === _thing;
})
});
console.log(newStuffList)
OR the magic by Deepak in javascript:
const stuff = [
{"name": "shark", "location": "somewhere", "number":10},
{"name": "shark", "location": "somewhereelse", "number":50},
{"name": "shark", "location": "somewhere", "number":25},
{"name": "turtle", "location": "anotherplace", "number":1},
{"name": "elephant", "location": "greatplace", "number":50},
{"name": "elephant", "location": "greatplace", "number":75}
]
var computed = [];
for(var element of stuff){
let computedElement = computed.find((ele) => ele.location == element.location);
if (computedElement){
computedElement.number += element.number;
}
else{
computed.push(element);
}
}
console.log(computed)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | DLBPointon |
| Solution 2 | |
| Solution 3 |
