Make new array that fills in missing values using lodash

2.6k views Asked by At

I have an array of objects which have a property of date in milliseconds. Note that the first three objects have the same date, but a different value.

var data = [
{"date":"1420070400000","value":53,"lat":"41.8089","lon":"-88.0111","regType":"Client","jobRole":"Other"},
{"date":"1420070400000","value":376,"lat":"41.8089","lon":"-88.0111","regType":"Client","jobRole":"Other"},
{"date":"1420070400000","value":43,"lat":"41.8089","lon":"-88.0111","regType":"Client","jobRole":"Other"},
{"date":"1420156800000","value":410,"lat":"41.8089","lon":"-88.0111","regType":"Client","jobRole":"Other"},
{"date":"1420329600000","value":210,"lat":"41.8089","lon":"-88.0111","regType":"Client","jobRole":"Other"}
];

console.log(data) shows this for the first object:

date: "1420070400000"jobRole: "Other"lat: "41.8089"lon: "-88.0111"regType: "Client"value: 53

Then, I have a second array of dates in milliseconds covering all possible dates between the earliest and latest dates of the first array.

var earliestDate = 1420070400000;
var latestDate = 1420329600000;
var list = [];
for (var i = earliestDate; i <= latestDate; i += 86400000) {
    list.push(i);
}

And console.log(list) shows this for that array:

[1420070400000, 1420156800000, 1420243200000, 1420329600000]

Note that the third date 1420243200000 is a date that exists between the earliest and latest dates, but is not in the original array of objects. That original array does not include every date in the range.

I want a resulting array of objects (like the first one), but with every date in the range. So, when a date was not present in the original array, now it is and it has new values assigned to its other properties.

I am trying to use _.find in lodash.

var newData = list.map(function(dateValue) {
    return _.find(data, { date: dateValue }) || {date: dateValue, value: 0, lat: "no lat value", lon: "no lon value", regType: "no regType value", jobRole: "no jobRole value" };
});

However, console.log(newData); shows this (here's the first object for example), which is assigning the new values to an existing date, which I don't want:

date: 1420070400000jobRole: "no jobRole value"lat: "no lat value"lon: "no lon value"regType: "no regType value"value: 0

Also, it is returning only 4 objects when there were originally five. What am I missing?

Here's the JSFIDDLE where you can inspect element. Thanks!

2

There are 2 answers

1
theRemix On BEST ANSWER

is this your desired result

[ { date: '1420070400000',
    value: 53,
    lat: '41.8089',
    lon: '-88.0111',
    regType: 'Client',
    jobRole: 'Other' },
  { date: '1420070400000',
    value: 376,
    lat: '41.8089',
    lon: '-88.0111',
    regType: 'Client',
    jobRole: 'Other' },
  { date: '1420070400000',
    value: 43,
    lat: '41.8089',
    lon: '-88.0111',
    regType: 'Client',
    jobRole: 'Other' },
  { date: '1420156800000',
    value: 410,
    lat: '41.8089',
    lon: '-88.0111',
    regType: 'Client',
    jobRole: 'Other' },
  { date: '1420329600000',
    value: 410,
    lat: '41.8089',
    lon: '-88.0111',
    regType: 'Client',
    jobRole: 'Other' },
  { date: '1420243200000',
    value: 0,
    lat: 'no lat value',
    lon: 'no lon value',
    regType: 'no regType value',
    jobRole: 'no jobRole value' } ]

here you can use _.find

first, create a list of all dates you want to make sure appear in your data. then forEach to add the defaults that do not exist.

var earliestDate = 1420070400000;
var latestDate = 1420329600000; // inclusive

(function(begin,end,increment){ 
  // faux array comprehension
  return Array.apply(null, {length: Math.floor((end+increment-begin)/increment)})
         .map(Number.call, function (n) {
            return begin + (n*increment);
         });
  })(earliestDate, latestDate, 86400000)
  .forEach(function (fillDate) {
    if( _.find(data,function (row) {
          return parseInt(row.date) === fillDate;
        }) === undefined){
      data.push({"date":fillDate.toString(),"value": 0,"lat": "no lat value","lon": "no lon value","regType": "no regType value","jobRole": "no jobRole value" });
    }
  });

console.log(data);

if you need it ordered by date, then you can .sort data after. this isn't the most optimal way to do it, however it will work without changing your data structure.

fiddle link: http://jsfiddle.net/96xmjf3x/

4
Dave Newton On

Two issues:

  1. The date in data is a string; you're comparing it against numbers. See http://jsfiddle.net/davelnewton/dst9nk6p/1/ for the easy fix.
  2. The list array only has four elements, so you'll only get four values back. You're doing the map backwards; you want to iterate over data's keys and check to see if they're in list.

This will make things inefficient if list gets big; you might want to put those values into a map as well so the array doesn't have to be iterated for each data.