Reputation: 1932
I have a javascript object, and array of id's:
var ids = [46,44,49,47];
var obj = {
"46": {
"group": "A",
"temp": 26,
"humid": 36
},
"44": {
"group": "B",
"temp": 19,
"humid": 32
},
"49": {
"group": "B",
"temp": 20,
"humid": 31
},
"47": {
"group": "A",
"temp": 24,
"humid": 32
}
};
I want to get the average 'temp'
of each 'group'
. How can I do this?
I found other examples that would solve this problem, however, these examples assume that 'group'
will always be the same. In my case, 'group'
is always changing.
So essentially I need to find how many unique groups exist, then return the average 'temp'
value of each.
I attempted to use some for loops nested together, but it got complicated quickly...
Expected Output:
avgTemps = {"A":25, "B": 19.5}
Upvotes: 1
Views: 77
Reputation: 22320
you can do that:
const
ids = [46,44,52,49,47]
, obj =
{ '46': { group: 'A', temp: 26, humid: 36 }
, '44': { group: 'B', temp: 19, humid: 32 }
, '49': { group: 'B', temp: 20, humid: 31 }
, '47': { group: 'A', temp: 24, humid: 32 }
, '64': { group: 'A', temp: 25, humid: 32 }
}
, avgTemps =
ids.reduce((rO,key)=>{if (obj[key]) rO.push(obj[key]);return rO},[])
.reduce((res,o,_,Oe)=>
{
if(!res[o.group])
{
let grp = Oe.filter(x=>x.group===o.group)
.map(y=>y.temp)
res[o.group] = grp.reduce((sum,t)=>sum+t,0) / grp.length
}
return res
},{})
console.log( avgTemps )
.as-console-wrapper {max-height: 100%!important;top:0 }
Upvotes: 0
Reputation: 431
First of all, I have taken all the unique groups in a set for distinction. Then created an array of objects is manipulated and eventually all the average, count, and the total is assigned in the array of objects. And the expected result is generated.
var ids = [46, 44, 49, 47];
var obj = {
"46": {
"group": "A",
"temp": 26,
"humid": 36
},
"44": {
"group": "B",
"temp": 19,
"humid": 32
},
"49": {
"group": "B",
"temp": 20,
"humid": 31
},
"47": {
"group": "A",
"temp": 24,
"humid": 32
}
};
var groups = new Set()
Object.keys(obj).forEach(element => {
groups.add(obj[element].group);
});
var tempAvgByGroups = [];
const avgTemp = {}
groups.forEach(element => {
const groupObj = {
"group": element,
"average": 0,
"count": 0,
"total": 0,
}
Object.keys(obj).forEach(item => {
if (element === obj[item]["group"]) {
groupObj["count"] = groupObj["count"] + 1;
groupObj["total"] = groupObj["total"] + obj[item]["temp"]
}
});
groupObj["average"] = groupObj["total"] / groupObj["count"];
tempAvgByGroups.push(groupObj);
avgTemp[element] = groupObj["average"]
});
console.log(avgTemp);
Upvotes: 0
Reputation: 1372
One more example in functional style)
function avg(vals: number[]): number {
return vals.reduce((a, b) => a + b) / vals.length;
}
function groupBy<Item, Desc extends string | number>(descriminator: (item: Item) => Desc) {
return (items: Item[]): Record<Desc, Item[]> => items.reduce((groups, item) => ({
...groups,
[descriminator(item)]: [...(groups[descriminator(item)] || []), item]
}), {} as Record<Desc, Item[]>);
}
function mapValues<From, To>(mapper: (from: From) => To) {
return (record: Record<string, From>): Record<string, To> => Object.assign(
{} as Record<string, To>,
...Object.keys(record).map(key => ({
[key]: mapper(record[key])
}))
)
}
const groups = groupBy(
({ group }: Item) => group
)(
Object.values(obj)
);
const avgTemps = mapValues(
(groupItems: Item[]) => avg(groupItems.map(({ temp }) => temp))
)(
groups
);
Upvotes: 0
Reputation: 350310
Create the target object first with sums and counts, and then divide those to averages:
function getAvgTemp(obj) {
let data = Object.values(obj);
let result = Object.fromEntries(data.map(({group}) => [group, { sum: 0, count: 0 }]));
for (let {group, temp} of data) {
let o = result[group];
o.count++;
o.sum += temp;
}
for (let key of Object.keys(result)) {
result[key] = result[key].sum / result[key].count;
}
return result;
}
// Demo
var obj = {"46": {"group": "A","temp": 26,"humid": 36},"44": {"group": "B","temp": 19,"humid": 32},"49": {"group": "B","temp": 20,"humid": 31},"47": {"group": "A","temp": 24,"humid": 32}};
let avgTemp = getAvgTemp(obj);
console.log(avgTemp);
Note that the ids
array seems overkill, since the properties of the object can be collected with Object.keys
.
Upvotes: 1
Reputation: 649
This should be a little bit shorter:
let output = {};
for (let group in obj) {
const groupName = obj[group]['group'];
if(!output[groupName]) {
output[groupName] = obj[group]['temp'];
} else {
output[groupName] = (output[groupName] + obj[group]['temp'])/2;
}
}
console.log(output);
Upvotes: 1
Reputation: 1233
You can use Object.keys(obj)
to get each ids of the group.
Then you can get values from this group like this:
const obj = {
"46": {
"group": "A",
"temp": 26,
"humid": 36
},
"44": {
"group": "B",
"temp": 19,
"humid": 32
},
"49": {
"group": "B",
"temp": 20,
"humid": 31
},
"47": {
"group": "A",
"temp": 24,
"humid": 32
}
};
Object.keys(obj).map((id) => console.log(`Temp of id ${id} is ${obj[id].temp}`))
We can create the object with group values.
Now if you can map your obj, let's create the average value of each group.
const obj = {
"46": {
"group": "A",
"temp": 26,
"humid": 36
},
"44": {
"group": "B",
"temp": 19,
"humid": 32
},
"49": {
"group": "B",
"temp": 20,
"humid": 31
},
"47": {
"group": "A",
"temp": 24,
"humid": 32
}
};
const groups = {};
Object.keys(obj).map((id) => {
if(!!groups[obj[id].group]) {
groups[obj[id].group].push(obj[id].temp);
} else {
groups[obj[id].group] = [obj[id].temp]
}
})
console.log(groups)
Then finally we can count average temps.
const obj = {
"46": {
"group": "A",
"temp": 26,
"humid": 36
},
"44": {
"group": "B",
"temp": 19,
"humid": 32
},
"49": {
"group": "B",
"temp": 20,
"humid": 31
},
"47": {
"group": "A",
"temp": 24,
"humid": 32
}
};
const groups = {};
Object.keys(obj).forEach((id) => {
if(!!groups[obj[id].group]) {
groups[obj[id].group].push(obj[id].temp);
} else {
groups[obj[id].group] = [obj[id].temp]
}
})
function getAvg(grades) {
const total = grades.reduce((acc, c) => acc + c, 0);
return total / grades.length;
}
Object.keys(groups).forEach((group) => {
groups[group] = getAvg(groups[group])
})
console.log(groups)
Upvotes: 1
Reputation: 1025
In a first step, you obtain a list of unique group names present in the data. Then, you filter out the temperatures for each group and compute the average.
You can also use lodash functions for removing duplicate entries from a list (_.uniq
) and to sum an array of numbers (_.sum
).
var ids = [46,44,49,47];
var obj = {
"46": {
"group": "A",
"temp": 26,
"humid": 36
},
"44": {
"group": "B",
"temp": 19,
"humid": 32
},
"49": {
"group": "B",
"temp": 20,
"humid": 31
},
"47": {
"group": "A",
"temp": 24,
"humid": 32
}
};
function onlyUnique(value, index, self) {
return self.indexOf(value) === index;
}
let groups = Object.values(obj).map((o)=>o.group).filter(onlyUnique)
for (let group of groups) {
let temps = Object.values(obj).filter((o)=>o.group===group).map((o)=>o.temp)
let avgtmp = temps.reduce((pv, cv) => pv + cv, 0)/temps.length;
console.log(`group ${group} has an avg tmp of ${avgtmp}`)
}
// OUTPUT
// group B has an avg tmp of 19.5
// group A has an avg tmp of 25
Upvotes: 1