Ajeeb Kalathingalthodi
Ajeeb Kalathingalthodi

Reputation: 168

How to get the most recent mood for each hour in javascript

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"
  }
];

JsFiddle here

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

Answers (3)

The Alpha
The Alpha

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

AncientSwordRage
AncientSwordRage

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:

  • Group the moods by hour
    • Get the hour from the time part of the mood objects
    • if that hour has been seen before, add the mood to it
    • otherwise create a new array for that hour
  • Find the latest mood in each hour
    • return that object instead of the array of ojects.

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

Cody Geisler
Cody Geisler

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

Related Questions