If I have an array of objects and there are certain objects that have the same name/property (in my case there are 2 instances of objects with a name of "highway"), how can I remove these objects from the array and add a new object with that contains data from both?
const data = [
{ "data": [ { "x": "sensor_error_code", "y": [ 0, 9 ] } ], "name": 123 },
{ "data": [ { "x": "road_type", "y": [ 15, 24 ] } ], "name": "city" },
{ "data": [ { "x": "road_type", "y": [ 0, 14 ] } ], "name": "highway" },
{ "data": [ { "x": "road_type", "y": [ 25, 30 ] } ], "name": "highway" },
{ "data": [ { "x": "weather", "y": [ 0, 8 ] } ], "name": "rain" },
{ "data": [ { "x": "weather", "y": [ 9, 24 ] } ], "name": "sun" },
{ "data": [ { "x": "special_object", "y": [ 5, 15 ] } ], "name": true }
];
e.g. having one instance of "highway" with a data object containing the values from both:
{ "data": [ { "x": "road_type", "y": [ 0, 14 ] }, { "x": "road_type", "y": [ 25, 30 ] } ], "name": "highway" }
So far I've tried to make a new empty object and loop over the data array, accumulating that empty object with names and values from that array. I was planning on converting that object to an array in the end. The code I've used is below:
const myData = {};
atts.forEach(att => {
if (myData[att.name]) {
myData[att.name].push(att.data)
} else {
myData[att.name] = att.data;
}
})
console.log(myData)
However, the code I've used above involves some additional manipulation to make the data ready for consumption by a library and I was wondering if there are simpler ways to achieve my goal?
Your solution has a decent start. There are only 2 problems with your solution:
You need to "unwrap" the array when pushing it
You need to combine them all together at the end
const myData = {};
atts.forEach(att => {
if (myData[att.name]) {
myData[att.name].push(...att.data) // Notice this change
} else {
myData[att.name] = att.data;
// or if you don't want to alter the original data
myData[att.name] = [...att.data]; // basically a shallow copy
}
})
const result = [];
for (const key in myData) {
result.push({ data: myData[key], name: key });
}
console.log(result);
You can use .reduce() (to convert your array into an aggregated value) along with .findIndex() (this helps in finding if data from same category exists in the new array you are making)
const atts = [
{ "data": [ { "x": "sensor_error_code", "y": [ 0, 9 ] } ], "name": 123 },
{ "data": [ { "x": "road_type", "y": [ 15, 24 ] } ], "name": "city" },
{ "data": [ { "x": "road_type", "y": [ 0, 14 ] } ], "name": "highway" },
{ "data": [ { "x": "road_type", "y": [ 25, 30 ] } ], "name": "highway" },
{ "data": [ { "x": "weather", "y": [ 0, 8 ] } ], "name": "rain" },
{ "data": [ { "x": "weather", "y": [ 9, 24 ] } ], "name": "sun" },
{ "data": [ { "x": "special_object", "y": [ 5, 15 ] } ], "name": true }
];
let myData = atts.reduce((agg, x) => {
let isIndex = agg.findIndex(a => a.name == x.name);
if(isIndex > -1) agg[isIndex].data.push(x.data[0]);
else {
agg.push({data : x.data , name : x.name});
}
return agg;
},[]);
console.log(myData)
A different approach using reduce - tracking the items by keys and merging the arrays of duplicate objects
const combined = Object.entries(data.reduce((b,a) => {
// our result will be an object so wrap it in Object.entries so we can iterate through to finish
if (b.hasOwnProperty(a.name)) b[a.name].data = [...b[a.name].data, ...a.data];
// if the property exists, merge the 'y' array
else b[a.name]=a;
// otherwise add to the object
return b;
},{})).map(e => e[1])
// finally map the result out to the desired format
const data = [
{ "data": [ { "x": "sensor_error_code", "y": [ 0, 9 ] } ], "name": 123 },
{ "data": [ { "x": "road_type", "y": [ 15, 24 ] } ], "name": "city" },
{ "data": [ { "x": "road_type", "y": [ 0, 14 ] } ], "name": "highway" },
{ "data": [ { "x": "road_type", "y": [ 25, 30 ] } ], "name": "highway" },
{ "data": [ { "x": "weather", "y": [ 0, 8 ] } ], "name": "rain" },
{ "data": [ { "x": "weather", "y": [ 9, 24 ] } ], "name": "sun" },
{ "data": [ { "x": "special_object", "y": [ 5, 15 ] } ], "name": true }
];
const combined = Object.entries(data.reduce((b,a) => {
if (b.hasOwnProperty(a.name)) b[a.name].data[0].y = [...b[a.name].data[0].y, ...a.data[0].y];
else b[a.name]=a;
return b;
},{})).map(e => e[1])
console.log(combined)
Related
Hi I am getting data from API but I want my data in different format so that I can pass later into a function. I want to change the names of keys into a different one becasuse I have created a chart and it only draws if I send it data in certain way
This is what I am getting from API
data = {
"status": "success",
"from": "DB",
"indice": "KSE100",
"data": [
{
"stock_sector_name": "Tc",
"sector_score": "0828",
"stocks": [
{
"stock_symbol": "TRG",
"stock_score": 44
},
{
"stock_symbol": "SYS",
"stock_score": 33
}
]
},
{
"stock_sector_name": "OIL",
"sector_score": "0828",
"stocks": [
{
"stock_symbol": "FFS",
"stock_score": 44
},
{
"stock_symbol": "SMS",
"stock_score": 33
}
]
},
]
}
But I want my data to look like this like this
data = {
"name": "KSE100",
"children": [
{
"name": "A",
'points': -9,
"children": [
{
"stock_title": "A",
"value": 12,
},
{
"stock_title": "B",
"value": 4,
},
]
},
{
"name": "B",
'points': 20,
"children": [
{
"stock_title": "A",
"value": 12,
},
{
"name": "B",
"value": 4,
},
]
},
]
}
Like I want to replace
stock_sector_name = name
sector_score = value
stocks = children
stock_symbol = name
stock_score = value
I have been trying this for so much time but sill could not figured it out
function convert(d){
return {
name : d.indice,
children : d.data.map(y=>{
return {
name : y.stock_sector_name,
points : y.sector_score,
children : y.stocks.map(z=>{
return {
stock_title: z.stock_symbol,
value : z.stock_score
}
})
}
})
}
}
You can do something like this
const data = {
"status": "success",
"from": "DB",
"indice": "KSE100",
"data": [{
"stock_sector_name": "Tc",
"sector_score": "0828",
"stocks": [{
"stock_symbol": "TRG",
"stock_score": 44
},
{
"stock_symbol": "SYS",
"stock_score": 33
}
]
},
{
"stock_sector_name": "OIL",
"sector_score": "0828",
"stocks": [{
"stock_symbol": "FFS",
"stock_score": 44
},
{
"stock_symbol": "SMS",
"stock_score": 33
}
]
},
]
}
const data2 = {
"name": "KSE100",
"children": [{
"name": "A",
'points': -9,
"children": [{
"stock_title": "A",
"value": 12,
},
{
"stock_title": "B",
"value": 4,
},
]
},
{
"name": "B",
'points': 20,
"children": [{
"stock_title": "A",
"value": 12,
},
{
"name": "B",
"value": 4,
},
]
},
]
}
//stock_sector_name = name
//sector_score = value
//stocks = children
//stock_symbol = stock_title
//stock_score = value
const keys = {
stock_sector_name: "name",
sector_score: "points",
stocks: "children",
stock_symbol: "stock_title",
stock_score: "value",
indice: "name",
//data: "children"
}
const rename = (value) => {
if (!value || typeof value !== 'object') return value;
if (Array.isArray(value)) return value.map(rename);
return Object.fromEntries(Object
.entries(value)
.map(([k, v]) => [keys[k] || k, rename(v)])
);
}
renamedObj = rename(data);
console.log(renamedObj);
I am making an API call from Angular 5, the response is coming in below format.
{ "metadata":{
"lastSyncTime":"2000-11-21T16:07:53",
"dataFromDB":true
},
"allocationReports":[ {
"allocatedUserCount":100,
"healthGoalName":"Eat Healthier"
},
{
"allocatedUserCount":130,
"healthGoalName":"Feel Happier"
},
{
"allocatedUserCount":150,
"healthGoalName":"Quit Smoking"
}
],
"overall":{
"usersWithGoalCount":0,
"registeredCount":500,
"eligibleCount":280
}
}
I need to transform this data into a list of lists(or Array of Arrays) so that I can plot multiple donut charts on this data. I have tried with multiple methods like using .map, but getting all the values in single list. How can I build the data in below format.
The required format is :
[
[
{ "x": "Eat Healthier", "y": 100 },
{ "x": "Total registered", "y": 500 }
],
[
{ "x": "Feel Happier", "y": 130 },
{ "x": "Total registered", "y": 500 }
],
[
{ "x": "Quit Smoking", "y": 150 },
{ "x": "Total registered", "y": 500 }
]
]
The total registered value will come from overall.registeredCount
try this
ob={"metadata":{ "lastSyncTime":"2000-11-21T16:07:53", "dataFromDB":true }, "allocationReports":[ { "allocatedUserCount":100, "healthGoalName":"Eat Healthier" }, { "allocatedUserCount":130, "healthGoalName":"Feel Happier" }, { "allocatedUserCount":150, "healthGoalName":"Quit Smoking" } ], "overall":{ "usersWithGoalCount":0, "registeredCount":500, "eligibleCount":280 } }
r=ob.allocationReports.map(o=>{return [{x:o.healthGoalName,y:o.allocatedUserCount},{x: "Total registered", y: ob.overall.registeredCount }]})
console.log(r)
I have an array of two objects which has another array of objects, i want the count of all objects of property "value" in the following sample.
var data = [
{
"x": "123",
"values": [
{
"a": "1"
},
{
"b": "2"
}
]
}, {
"y": "123",
"values": [
{
"a": "1"
},
{
"b": "2"
}
]
}
];
I have used the following logic :-
let _data = data.RESULT;
console.log(JSON.stringify(_data));
_data.forEach(element => {
this.someObj = element;
});
The expected result should be the length of values property, i.e. 4
If you want to find only length of "values" array then you need to do this
data = [
{
"x": "123",
"values": [
{
"a": "1"
},
{
"b": "2"
}
]
}, {
"y": "123",
"values": [
{
"a": "1"
},
{
"b": "2"
}
]
}
]
length = 0;
constructor() {
this.data.forEach((d) => {
length = length + d.values.length;
});
console.log('length', length);
}
https://stackblitz.com/edit/angular-3daqcy?file=src%2Fapp%2Fapp.component.ts
Created a function that adds the lengths of the values array
var arr = [
{
"x": "123",
"values": [
{
"a": "1"
},
{
"b": "2"
}
]
}, {
"y": "123",
"values": [
{
"a": "1"
},
{
"b": "2"
}
]
}
]
function getKeysLength(arr){
var count = 0;
arr.forEach((val)=>{count= count+ val.values.length})
return count
}
var ans = getKeysLength(arr);
console.log("ans",ans);
If you want to do it in a single line then you can do it with map and reduce,map creates a new array with the elements as the length of the values property and reduce calculates the sum of the new array elements . Which gives you the sum of the length of all values property arrays.
Here is the code below -
let data = [
{
"x": "123",
"values": [
{
"a": "1"
},
{
"b": "2"
}
]
}, {
"y": "123",
"values": [
{
"a": "1"
},
{
"b": "2"
}
]
}
];
let totalLength = data.map(x => x.values.length).reduce((a,b) => a+b,0);
console.log(temparr);
Here is a working Stackblitz with Angular 6
https://stackblitz.com/edit/hello-angular-6-ewa5tb?file=src/app/app.component.ts
I am working to sort an array of objects in descending order using pure javascript. I initially thought that a JSON.stringify method was causing the issue, as described [here][1]. Apparently JSON.stringify does not preserve the order of objects by design. Give the below array of objects I seem to get a random sort order using the following code where I sort the array of objects and then derive the weight property of the first object in the array.
var byWeight = objArray.slice(0);
var sorted = byWeight.sort(function(a,b) { return b.weight - a.weight; } );
sorted[0].something.weight;
On distinct runs of this code, I seem to randomly derive .29 or .35 for the weight. Why is this occurring?
Here is the array:
[
{
"something": {
"terms": [
{
"elements": {
"number": {
"span": [
9,
10
],
"value": "1"
}
},
"span": [
9,
12
],
"value": "1g",
"label": "grams"
}
],
"span": [
9,
12
],
"weight": 0.29,
"value": "1gm"
}
},
{
"something": {
"terms": [
{
"elements": {
"number": {
"span": [
16,
18
],
"value": "30"
}
},
"span": [
16,
20
],
"value": "30ml",
"label": "liters"
}
],
"span": [
16,
20
],
"weight": 0.35,
"value": "30ml"
}
}
]
You have the wrong reference. Change this
var sorted = byWeight.sort(function(a,b) { return b.weight - a.weight; } );
to (watch .something.)
byWeight.sort(function (a, b) { return b.something.weight - a.something.weight; });
Working model:
var data = [
{
"something": {
"terms": {
"span": [
9,
12
],
"value": "1g",
"label": "grams"
}
,
"span": [
9,
12
],
"weight": 0.29,
"value": "1gm"
}
},
{
"something": {
"terms": {
"span": [
16,
20
],
"value": "30ml",
"label": "liters"
}
,
"span": [
16,
20
],
"weight": 0.35,
"value": "30ml"
}
}
];
var sorted = data.slice(0);
sorted.sort(function (a, b) {
return b.something.weight - a.something.weight; // desc!
});
document.write('<pre>' + JSON.stringify(sorted, 0, 4) + '</pre>');
Your objArray is poorly formatted, "terms" shouldn't be an array if it contains key-indexed elements like "span", "value", and "label' it should be an object; then your sort is looking in the wrong place, it should be looking at a.something.weight/b.something.weight instead. jsfiddle.net/3qgtn9r1
var objArray = [
{
"something": {
"terms": {
"span": [
9,
12
],
"value": "1g",
"label": "grams"
},
"span": [
9,
12
],
"weight": 0.29,
"value": "1gm"
}
},
{
"something": {
"terms": {
"span": [
16,
20
],
"value": "30ml",
"label": "liters"
},
"span": [
16,
20
],
"weight": 0.35,
"value": "30ml"
}
}
];
var byWeight = objArray.slice(0);
var sorted = byWeight.sort(function(a,b) { return a.something.weight - b.something.weight; } );
console.log(sorted[0].something.weight);
I am using the nvd3 library to make a bar graph, and I'm running into some trouble trying to figure out how to use my object properly. If I try and use the object that I created from a JSON file, the graph doesn't behave properly(see the picture that I've provided. the bars are off center). I'm building off of a multi-bar graph example so my guess is that it's still trying to display the graph as if there would be multiple bars for each x value.
function dataFactory(seriesNum, perSeries) {
return new d3.range(0,seriesNum).map(function(d,i) { return { //will return the amount of streams to be seen on the graph
key: 'Stream ' + i,
values: new d3.range(0,perSeries).map( function(f,j) {
return {
y: 10 + Math.random()*100, // a random value is given to y and the range of 0-perSeries is put into j
x: j
}
})
};
});
}
However, using the above function and calling it to be used for data works properly. Does anyone know what I have to do to get my object to behave like the object that comes from this function?
My json file if you need to see it:
{
"Member1": {
"key":"test10",
"values": [
{
"x": "test10",
"y": 20
}
]
},
"Member2":{
"key":"test9",
"values": [
{
"x": "test9",
"y": 10
}
]
},
"Member3":{
"key":"test8",
"values": [
{
"x": "test8",
"y": 4
}
]
},
"Member4":{
"key":"test7",
"values": [
{
"x": "test7",
"y": 12
}
]
},
"Member5":{
"key":"test6",
"values": [
{
"x": "test6",
"y": 30
}
]
},
"Member6":{
"key":"test5",
"values": [
{
"x": "test5",
"y": 8
}
]
}
,
"Member7":{
"key":"test4",
"values": [
{
"x": "test4",
"y": 27
}
]
},
"Member8":{
"key":"test3",
"values": [
{
"x": "test3",
"y": 17
}
]
},
"Member9":{
"key":"test2",
"values": [
{
"x": "test2",
"y": 2
}
]
},
"Member10":{
"key":"test11",
"values": [
{
"x": "test11",
"y": 53
}
]
},
"Member11":{
"key":"test13",
"values": [
{
"x": "test13",
"y": 55
}
]
},
"Member12":{
"key":"test14",
"values": [
{
"x": "test14",
"y": 104
}
]
},
"Member13":{
"key":"test15",
"values": [
{
"x": "test15",
"y": 12
}
]
},
"Member14":{
"key":"test16",
"values": [
{
"x": "test16",
"y": 87
}
]
}
}