Search code examples
node.jstypescriptlodash

Merge multiple object arrays and removing duplicates based on optional property


Say if there are arrays like:

const arr1 = [
   { "id": "1", "type": "sales" },
   { "id": "2", "type": "finance" }
]

const arr2 = [
   { "type": "sales" },
   { "id": "2", "type": "finance" }
]

const arr3 = [
   { "id": "1", "type": "sales" },
   { "type": "sales" },
   { "type": "finance" }
]

As you can see, id is optional. I need to merge arrays in such way that uniqueness should be based on id if present, else entire rest of the object. ex. here merged array would be:

[ 
  { "id": "1", "type": "sales" }, 
  { "type": "sales" }, 
  { "id": "2", "type": "finance" }, 
  { "type": "finance" } 
]

loadash has .unionBy but optional uniqueness doesn't work.

const result = _.unionBy(arr1, arr2, arr3, 'id')

Probably I have to iterate through each, but I was wondering if there is any simpler alternative for this.


Solution

  • Instead of _.unionBy you can use _.unionWith which accepts a custom comparator. The logic for comparison is:

    1. Compare by ID if both items have an ID.
    2. Compare by type if both items do not have an ID.
    3. Consider them different if one has an ID the other not.

    const arr1 = [
       { "id": "1", "type": "sales" },
       { "id": "2", "type": "finance" }
    ]
    
    const arr2 = [
       { "type": "sales" },
       { "id": "2", "type": "finance" }
    ]
    
    const arr3 = [
       { "id": "1", "type": "sales" },
       { "type": "sales" },
       { "type": "finance" }
    ]
    
    const result = _.unionWith(arr1, arr2, arr3, (item1, item2) => {
      const item1HasId = _.has(item1, "id");
      const item2HasId = _.has(item2, "id");
      
      if (item1HasId && item2HasId) //if both have ID...
        return item1.id === item2.id; // ...compare by ID
        
      if (!item1HasId && !item2HasId) //if neither has ID...
        return item1.type === item2.type; // ...compare by type
        
      return false; // otherwise not equal
    });
    
    console.log(result);
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>