0

I've got an array of objects which have a property in common 'label'. But some of them have properties that others don't :

const array = [
    {
        label: 'thing',
        type: 'reg',
    },
    {
        label: 'thing',
        type: 'ville',
        id: 1,
    },
    {
        label: 'another_thing',
        type: 'ville',
        id: 2,
    },
    {
        label: 'something',
        type: 'dpt',
    }
];

And I want duplicates (those objects with the same 'label' value) in this array to be removed and to keep only those which have the 'id' property. I tried to do it with _.uniqBy but it takes the first occurrence of the duplicated object and doesn't take the id property in consideration.

So my final array should look like because the duplicate with the same 'label' value but which has no id property has been removed :

const array = [
    {
        label: 'thing',
        type: 'ville',
        id: 1,
    },
    {
        label: 'another_thing',
        type: 'ville',
        id: 2,
    },
    {
        label: 'something',
        type: 'dpt',
    }
];
3
  • 1
    Please visit the help center, take the tour to see what and How to Ask. Do some research, search for related topics on SO; if you get stuck, post a minimal reproducible example of your attempt, noting input and expected output using the [<>] snippet editor.
    – mplungjan
    Commented Oct 8, 2020 at 12:12
  • 1
    You say "to keep only objects which have the 'id' property", but your final array has an entry with no "id" in it. I think you need to clarify this.
    – John
    Commented Oct 8, 2020 at 12:13
  • reduce and find
    – mplungjan
    Commented Oct 8, 2020 at 12:14

3 Answers 3

3

Reduce the array to a Map. If the item has an id or the label doesn't exist in the Map, add it to the Map. Convert the Map's .values() iterator to an array using Array.from():

const array = [{"label":"thing","type":"reg"},{"label":"thing","type":"ville","id":1},{"label":"something","type":"dpt"}];

const result = Array.from( // convert the Map's iterator to an array
  array.reduce((r, o) =>
    'id' in o || !r.has(o.label) ? // if the item has an id or it doesn't exist in the Map
      r.set(o.label, o) // add it to the Map and return the Map
      :
      r // just return the Map
  , new Map()
).values()); // convert to an iterator

console.log(result);

1

You can use a map to store items by their key and use a filter function to determine if an item is eligible to be overwritten.

const array = [
  { label: 'thing',     type: 'reg'          },
  { label: 'thing',     type: 'ville', id: 1 },
  { label: 'something', type: 'dpt'          }
];

const filterUnique = (list, key, filterFn) => [
  ...list.reduce((result, item) => {
    if (!result.has(item[key]) || filterFn(item)) {
      result.set(item[key], item);
    }
    return result;
  }, new Map()).values() ];

console.log(filterUnique(array, 'label', item => item.id));
.as-console-wrapper { top: 0; max-height: 100% !important; }

1

We can achieve this using Array.reduce and Object.values

const array = [{label:'thing',type:'reg'},{label:'thing',type:'ville',id:1},{label:'another_thing',type:'ville',id:2},{label:'something',type:'dpt'}];

const filterData = (data) => {
  const finalResult = data.reduce((res, obj) => {
  //Check if the object is already present in the `res` object with key as `obj.label`
  //If not found, add the obj to result
    if(!res[obj.label]) {
      res[obj.label] = obj;
    } else if(obj.hasOwnProperty("id")) {
    //If found, check the new obj has property `id`, if available then override 
    //result object with key as `obj.label` with new object
      res[obj.label] = obj
    }
    return res;
  }, {})

//Return the values of the finalResult object 
  return Object.values(finalResult);
}

console.log(filterData(array))
.as-console-wrapper {
  max-height: 100% !important;
}

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.