Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JS - Using Set() in Array with Objects

How can i use Set() in objects? I read the documentation, it works with values in array, but with objects it do not work. Why? I want to avoid duplicate items that has exacly the same values.

let nameList_one = [{ name: 'harry', id: 1 }, { name: 'john', id: 2 }, { 'name': 'trevor', id: 3  }]
let nameList_two = [{ name: 'harry', id: 1  }, { name: 'ron', id: 4  }, { name: 'jackson', id: 5  }]

let fullNameList = [...nameList_one , ...nameList_two ]

let filteredList = [...new Set(fullNameList)] // the output is the merge of two array, duplicating "harry".

Output:

[{ name: 'harry', id: 1 }, { name: 'john', id: 2 }, { 'name': 'trevor', id: 3 }, { name: 'harry', id: 1 }, { name: 'ron', id: 4 }, { name: 'jackson', id: 5 }]

Expected Output:

[{ name: 'harry', id: 1 }, { name: 'john', id: 2 }, { 'name': 'trevor', id: 3 }, { name: 'ron', id: 4 }, { name: 'jackson', id: 5 }]

Thanks!!

like image 780
Johnson Avatar asked Apr 13 '18 15:04

Johnson


People also ask

Can I use Set for array of objects in JavaScript?

Relevant info: How to customize object equality for Javascript Set - spoiler: "you can't" so you can't really use a Set for what you're trying to do. It simply doesn't do what you're looking for and can't be customized to do it either.

How do you Set an array of objects?

An Array of Objects is created using the Object class, and we know Object class is the root class of all Classes. We use the Class_Name followed by a square bracket [] then object reference name to create an Array of Objects.

Does JavaScript Set work with objects?

Sets are supposed to contain unique objects, but it doesn't work for objects in javascript.


2 Answers

This doesn't work with objects because they are not same objects:

{ name: 'harry', id: 1 } !== { name: 'harry', id: 1 }

A way that may work is:

let filteredList = [...new Set(fullNameList.map(JSON.stringify))].map(JSON.parse);

It cannot be recommended, because it uses serialization where it's unnecessary. Serialization will destroy object instances that cannot be serialized, will ignore non-enumerable properties and won't handle circular references. Objects that have different property order won't be removed as duplicates. Their properties should be sorted first. In case there are nested objects, keys should be sorted recursively. This makes this approach impractical.

If the objects are identified by one or several fields, Map with serialized fields as map keys can be used:

let filteredList = [
  ...new Map(fullNameList.map(obj => [`${obj.id}:${obj.name}`, obj]))
  .values()
];
like image 168
Estus Flask Avatar answered Nov 03 '22 01:11

Estus Flask


A nice way of doing this is to subclass Set.

class UniqueNameSet extends Set {
    constructor(values) {
        super(values);

        const names = [];
        for (let value of this) {
            if (names.includes(value.name)) {
                this.delete(value);
            } else {
                names.push(value.name);
            }
        }
    }
}

This gives you all the other methods/properties of Set, but adds the extra functionality you are looking for.

like image 35
lonesomeday Avatar answered Nov 03 '22 01:11

lonesomeday