Reputation: 18155
The first array is a master list of date objects containing unique javascript Date objects:
[
{'date': dateobject1, 'value': null},
{'date': dateobject2, 'value': null},
{'date': dateobject3, 'value': null},
etc...
]
The first array is a much smaller list of date objects containing a subset of the unique javascript Date objects, with the 'value' property always having a number rather than a null
:
[
{'date': dateobject3, 'value': 3117},
{'date': dateobject8, 'value': 14},
etc...
]
Keeping in mind the nuances of comparing date objects - https://stackoverflow.com/a/493018/538962 - what would be the most efficient way to merge these objects - in an environment where lodash 3.10.1 is available -
based on matching dates so that the merged array is a list of all dates: matches mean the 'value' becomes the numeric value, and otherwise the null
'value' is retained when there is no match?
[
{'date': dateobject1, 'value': null},
{'date': dateobject2, 'value': null},
{'date': dateobject3, 'value': 3117},
{'date': dateobject4, 'value': null},
{'date': dateobject5, 'value': null},
{'date': dateobject6, 'value': null},
{'date': dateobject7, 'value': null},
{'date': dateobject8, 'value': 14},
etc...
]
Upvotes: 4
Views: 2680
Reputation: 147403
You can use the built-in Array.prototype.map to create a new array from the existing array values.
Where you say:
The first array is a much smaller list of date objects containing a subset of the unique javascript Date objects
I'm assuming that dateobject3 is the same object in both arrays, not two different objects for the same date.
The following creates an index for the values array to save iterating over values for each member of data. It won't make a noticeable difference for small data sets (say less than 100 values), but will for larger ones (say more than a few hundred or a thousand).
var d0 = new Date(2017,1,1),
d1 = new Date(2017,1,2),
d2 = new Date(2017,1,3);
var data = [
{'date': d0, 'value': null},
{'date': d1, 'value': null},
{'date': d2, 'value': null}
];
var values = [
{'date': d1, 'value': 3117},
];
// Generate a values index, saves searching
// through values for each member of data
var indexes = values.map(obj => obj.date);
// Generate merged array
var merged = data.map(obj => {
var index = indexes.indexOf(obj.date);
return {date: obj.date, value: index > -1? values[index].value : obj.value};
});
console.log(merged)
If on the other hand the dates are different objects but with the same time value, then you need to compare the time value instead. A simple way to get the time value is to use unary +
, it just saves typing over getValue or getTime:
var data = [
{'date': new Date(2017,1,1), 'value': null},
{'date': new Date(2017,1,2), 'value': null},
{'date': new Date(2017,1,3), 'value': null}
];
var values = [
{'date': new Date(2017,1,2), 'value': 3117},
];
// Generate a values index using the date time value
// saves searching through values for each member of data
var indexes = values.map(obj => +obj.date);
// Generate merged array
var merged = data.map(obj => {
var index = indexes.indexOf(+obj.date);
return {date: obj.date, value: index > -1? values[index].value : obj.value};
});
console.log(merged)
If each date will only have one match, you can optimise further by removing matched indexes when they're matched so subsequent lookups are (possibly imperceptibly) faster.
Upvotes: 2
Reputation: 365
Think using a hashset would be one of the quicker ways https://codepen.io/TimCodes/pen/brQvbo?editors=0012
var masterListArr = [ { 'date' : new Date(), 'value' : 2 } , {'date' : new Date(2013, 13, 1), 'value' : 0}]
var secondListArr = [ { 'date' : new Date(), 'value' : null } , {'date' : new Date(2014, 13, 1), 'value' : null}]
var masterListHash = masterListArr.reduce(function(acc, cur, i) {
acc[cur['date'].getTime()] = cur['value'] ;
return acc;
}, {});
var mergedList = secondListArr.map(dateObj => {
var dateKey = dateObj.date.getTime()
if(masterListHash.hasOwnProperty(dateKey)){
dateObj.value = masterListHash[dateKey]
}
return dateObj
})
Upvotes: 0
Reputation: 12029
Nice question. I would use the reduce
method on the master list to see if the other list contains a matching date - if so merge the two objects and push to the new array, if not just push the object from the master list. Mind you this is using es6 - if es6 is not available to you in the environment you are using lodash has a reduce
and assign
method
const masterList = [/* ... */];
const otherArray = [/* ... */];
const mergedArray = masterList.reduce((a, b) => {
const match = otherArray.filter(({ date }) => date.getTime() === b.date.getTime());
if(match) {
a.push(Object.assign(b, match));
} else {
a.push(b);
}
return a;
}, []);
Upvotes: 0