Search code examples
javascriptecmascript-6lodash

Removing duplicate dates in two arrays using lodash/fp


I'm trying to take a more functional approach to displaying data and having trouble removing duplicate items from an array. What I'm trying to achieve is removing and/or merge items which are of the same date.

I've tried using the _.uniqBy but it just returns the list untouched it's because it's a date object and therefore.

new Date(2018, 4, 7) === new Date(2018, 4, 7) //false new Date(2018, 4, 7) == new Date(2018, 4, 7) //false

is there a way to deepMatch using uniqBy or another method of merging or removing duplicates in a functional approach.

note: objects/functions have been simplified to the problem.

const items = [{date: new Date(2018, 4, 7), wellbeing: 50}];
const days = [{date: new Date(2018, 4, 7)}, {date: new Date(2018, 4, 8)}];
const Row = (item) => item; // not real map just mock

function mapToRow(data) {
   return _.pipe([
    sortByDate,
    _.uniqBy('date'),
    _.map(Row)
  ])(data)
}
function sortByDate(array) {
  return array.sort((a, b) => {
    a = new Date(a.date);
    b = new Date(b.date);
    return a < b ? -1 : a > b ? 1 : 0;
  });
}

console.log(mapToRow(days.concat(items)));
<script src="https://cdn.jsdelivr.net/g/lodash@4(lodash.min.js+lodash.fp.min.js"></script>

can use lib such as moment

// expected outcome

[{date: new Date(2018, 4, 7), wellbeing: 50}, {date: new Date(2018, 4, 8)}]


Solution

  • You can use _.unionWith(), and check for equality using _.isEqual():

    const items = [{date: new Date(2018, 4, 7), wellbeing: 50}];
    const days = [{date: new Date(2018, 4, 7)}, {date: new Date(2018, 4, 8)}];
    
    const result = _.unionWith(
      (arrVal, othVal) => _.isEqual(arrVal.date, othVal.date),
      items,
      days
    );
    
    console.log(result);
    <script src="https://cdn.jsdelivr.net/g/lodash@4(lodash.min.js+lodash.fp.min.js"></script>

    With just ES6, you can reduce both arrays to a Map, and then spread the Map.values() back to array:

    const items = [{date: new Date(2018, 4, 7), wellbeing: 50}];
    const days = [{date: new Date(2018, 4, 7)}, {date: new Date(2018, 4, 8)}];
    
    const result = [...items.concat(days)
      .reduce((r, o) => {
        const time = o.date.getTime();
        return r.set(time, { ...r.get(time), ...o });
      }, new Map())
      .values()];
      
    console.log(result);