I'm trying to group an array by one property (year) and then create a nested array inside each year, listing the weeks with their total Total Distance and Max Avg Speed.
i.e.
[
{
"year": 2015,
"weeks": [
{week: 45, totalDistance: nnn, maxAvgSpeed: nnn},
{week: 46, totalDistance: nnn, maxAvgSpeed: nnn},
{week: 47, totalDistance: nnn, maxAvgSpeed: nnn}
...
This is what I have so far, but it says "activitiesByYear.forEach is not a function" even though activitiesByYear is an array as expected.
const activities = [
{
"id": 1,
"actvityYear": 2015,
"actvityWeek": 45,
"name": "One",
"avgSpeed": 1200,
"distance": 2
},
{
"id": 2,
"actvityYear": 2015,
"actvityWeek": 45,
"name": "Two",
"avgSpeed": 1403,
"distance": 6
},
{
"id": 3,
"actvityYear": 2015,
"actvityWeek": 46,
"name": "Three",
"avgSpeed": 1700,
"distance": 7
},
{
"id": 4,
"actvityYear": 2015,
"actvityWeek": 47,
"name": "Four",
"avgSpeed": 600,
"distance": 12
},
{
"id": 5,
"actvityYear": 2015,
"actvityWeek": 47,
"name": "Five",
"avgSpeed": 300,
"distance": 4
},
{
"id": 6,
"actvityYear": 2016,
"actvityWeek": 2,
"name": "Six",
"avgSpeed": 1800,
"distance": 15
}
]
function groupBy(objectArray, property) {
return objectArray.reduce((acc, obj) => {
const key = obj[property];
if (!acc[key]) {
acc[key] = [];
}
// Add object to list for given key's value
acc[key].push(obj);
return acc;
}, {});
}
const activitiesByYear = groupBy(activities, 'actvityYear');
let years = [];
activitiesByYear.forEach(year => {
let weeks = [];
year.reduce(function(result, value) {
const week = moment(value.actvityDate).week();
if (!result[week]) {
result[week] = { week: week, totalDistance: 0, maxAvgSpeed: value.avgSpeed };
weeks.push(result[week])
}
result[week].totalDistance = value.distance;
if (value.average_speed > result[week].maxAvgSpeed) result[week].maxAvgSpeed = value.average_speed;
return result;
}, {});
years.push({"year": year, "weeks": weeks})
})
console.log(years)
CodePudding user response:
You get TypeError: activitiesByYear.forEach is not a function
because activitiesByYear
is a object with the following keys: [ '2015', '2016' ]. Because the groupBy
returns an object. You can get the keys of the object with Object.keys()
.
For example:
const keys = Object.keys(activitiesByYear)
// [ '2015', '2016' ]
CodePudding user response:
Use Object#entries
to iterate over the year-items pairs
const activities = [
{ "id": 1, "actvityYear": 2015, "actvityWeek": 45, "name": "One", "avgSpeed": 1200, "distance": 2 },
{ "id": 2, "actvityYear": 2015, "actvityWeek": 45, "name": "Two", "avgSpeed": 1403, "distance": 6 },
{ "id": 3, "actvityYear": 2015, "actvityWeek": 46, "name": "Three", "avgSpeed": 1700, "distance": 7 },
{ "id": 4, "actvityYear": 2015, "actvityWeek": 47, "name": "Four", "avgSpeed": 600, "distance": 12 },
{ "id": 5, "actvityYear": 2015, "actvityWeek": 47, "name": "Five", "avgSpeed": 300, "distance": 4 },
{ "id": 6, "actvityYear": 2016, "actvityWeek": 2, "name": "Six", "avgSpeed": 1800, "distance": 15 }
];
function groupBy(objectArray, property) {
return objectArray.reduce((acc, obj) => {
const key = obj[property];
if (!acc[key]) { acc[key] = []; }
acc[key].push(obj);
return acc;
}, {});
}
const activitiesByYear = groupBy(activities, 'actvityYear');
let years = [];
Object.entries(activitiesByYear).forEach(([year, items]) => { // fix
let weeks = [];
items.reduce((result, value) => {
const week = value.actvityWeek;
if (!result[week]) {
result[week] = { week, totalDistance: 0, maxAvgSpeed: value.avgSpeed };
weeks.push(result[week])
}
result[week].totalDistance = value.distance;
if (value.average_speed > result[week].maxAvgSpeed) {
result[week].maxAvgSpeed = value.average_speed;
}
return result;
}, {});
years.push({ year, weeks });
});
console.log(years);