Reputation: 168
How do I filter an array to get the most recent mood for every hour?
Example data model:
var arr = [{
mood: "normal",
date: "29-7-2018",
time: "9:24 am"
},
{
mood: "normal",
date: "29-7-2018",
time: "9:34 am"
},
{
mood: "normal",
date: "29-7-2018",
time: "9:40 am"
},
{
mood: "normal",
date: "29-7-2018",
time: "10:14 am"
},
{
mood: "normal",
date: "29-7-2018",
time: "10:46 am"
},
{
mood: "normal",
date: "29-7-2018",
time: "2:04 pm"
},
{
mood: "normal",
date: "29-7-2018",
time: "2:14 pm"
},
{
mood: "normal",
date: "29-7-2018",
time: "3:01 pm"
}
];
let l = arr.length;
/* console.log("length - " + l); */
let _time = formatAMPM(new Date()).split(":")[0];
arr = arr.filter(obj => obj.time.split(":")[0] != _time);
/* l = arr.length; */
/* for (i = l; i > 0; i--) {
arr = arr.filter(obj => obj.time.split(":")[0] == _time);
// console.log("--Fil elem--");
// console.log(arr);
} */
console.log(arr);
function formatAMPM(date) {
var hours = date.getHours();
var minutes = date.getMinutes();
var ampm = hours >= 12 ? "pm" : "am";
hours = hours % 12;
hours = hours ? hours : 12; // the hour '0' should be '12'
minutes = minutes < 10 ? "0" + minutes : minutes;
var strTime = hours + ":" + minutes + " " + ampm;
return strTime;
}
Upvotes: 2
Views: 248
Reputation: 146269
You can group items by hour first, for example:
let arr = [...Your array of objects...];
let groupedByHour = arr.reduce(function(result, item) {
let hour = item.time.split(':')[0];
result[hour] = result[hour] || [];
result[hour].push(item);
return result;
}, {});
This will give you an object like this:
{
2:[
{mood: "normal", date: "29-7-2018", time: "2:04 pm"},
{mood: "normal", date: "29-7-2018", time: "2:14 pm"}
],
3: [
{mood: "normal", date: "29-7-2018", time: "3:01 pm"}
]
// and so on...
}
Now you have all items grouped by hour, so now you can loop over the object and sort the array using the date field by descending order, for example:
for(let key in groupedByHour) {
groupedByHour[key].sort(function(a, b) {
return a.time < b.time;
});
}
Now, you'll get the same object but the arrays are orderd, so it'll be something like this:
{
2:[
{mood: "normal", date: "29-7-2018", time: "2:14 pm"},
{mood: "normal", date: "29-7-2018", time: "2:04 pm"}
],
3: [
{mood: "normal", date: "29-7-2018", time: "3:01 pm"}
]
// and so on...
}
Now, in each hour, the first item of the array is the latest mood, so if you want to get all latest moods from each hour, then you can get it like this:
let moods = {};
for (let k in groupedByHour) {
moods[k] = groupedByHour[k][0];
}
// Log them out
console.log(moods);
Check the console.log here (Each key is an hour and the value is the latest mood).
Upvotes: 3
Reputation: 7645
I've writtten the skeleton of your solution by breaking it out into functions, with clear names and comments. These aren't finished but should start you on your way to understanding how to break down the problem.
Here are the steps:
var moods = [{
mood: "normal",
date: "29-7-2018",
time: "9:24 am"
},
{
mood: "normal",
date: "29-7-2018",
time: "9:34 am"
},
{
mood: "normal",
date: "29-7-2018",
time: "9:40 am"
},
{
mood: "normal",
date: "29-7-2018",
time: "10:14 am"
},
{
mood: "normal",
date: "29-7-2018",
time: "10:46 am"
},
{
mood: "normal",
date: "29-7-2018",
time: "2:04 pm"
},
{
mood: "normal",
date: "29-7-2018",
time: "2:14 pm"
},
{
mood: "normal",
date: "29-7-2018",
time: "3:01 pm"
}
];
// takes time as a string and returns an hour as a string
//not finished
function getHour(timeAsString) {
return "2";
}
// creates an object of arrays for each hour,
// one per hour
// ["1":[{...},{....}], ....
let groupMoodsByHour = (memo, current) => {
const hour = getHour(current);
if (memo[hour]) {
memo[hour].push(current);
} else {
memo[hour] = [current]
}
return memo;
};
// gets the most recent object from an array of moodObjects
function getLatestHour(arrayOfMoods) {
return arrayOfMoods[0];
}
let moodsByHour = moods.reduce(groupMoodsByHour,[]).map(getLatestHour);
console.log(moodsByHour);
This won't work as is but should be a very good start.
Upvotes: 2
Reputation: 8617
This isn't too bad with moment.js
and lodash
, but for performance you should really look at doing it another way, such as through a database query.
var arr = [{mood: "normal",date: "29-7-2018",time: "9:24 am"},{mood: "normal",date: "29-7-2018",time: "9:34 am"},{mood: "normal",date: "29-7-2018",time: "9:40 am"},{mood: "normal",date: "29-7-2018",time: "10:14 am"},{mood: "normal",date: "29-7-2018",time: "10:46 am"},{mood: "normal",date: "29-7-2018",time: "2:04 pm"},{mood: "normal",date: "29-7-2018",time: "2:14 pm"},{mood: "normal",date: "29-7-2018",time: "3:01 pm"}];
let moods = arr.map(o=>({mood:o.mood,datetime:moment(o.date + " "+ o.time,'DD-MM-YYYY hh:mm A')})).sort((a,b)=>a.datetime.valueOf() < b.datetime.valueOf())
moods = _.uniqWith(moods,(a,o)=>moment(o.datetime).startOf('hour').valueOf()===moment(a.datetime).startOf('hour').valueOf())
console.log(moods)
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.2/moment.min.js"></script>
Upvotes: 1