Set does not remove duplicate objects

Asked

Viewed 111 times

5

I have an array of objects and always to remove duplicate objects use the new Set(array), but this time did not work as expected.

In the following example, it is easier to understand. I’m passing my array with two duplicated objects, the "Multigases" and the "Temporary Ventilation", but I’m not getting to understand why it’s not working.

let arrayObjetos = [
  { descricao: 'Multigases', id: 1 },
  { descricao: 'Iluminação Temporária', id: 3 },
  { descricao: 'Ventilação Temporária', id: 2 },
  { descricao: 'Capa de cobertura.', id: 21 },
  { descricao: 'Multigases', id: 1 },
  { descricao: 'Ventilação Temporária', id: 2 },
  { descricao: 'Cadeado', id: 85 }
];
arrayObjetos = [...new Set(arrayObjetos)];

console.log(arrayObjetos);

1 answer

7


Consonant with the language specification (in free translation):

Objects Set are collections of values of the Ecmascript language. A distinct value can occur only once as an element of a collection Set. Separate values are broken down using the comparison algorithm SameValueZero.

This comparison algorithm is similar to that used by the already familiar operator ===. The only difference is that, for the Set, values NaN are always the same:

console.log(NaN === NaN); // false
console.log([...new Set([NaN, NaN])]); // [NaN] (somente 1, mas passamos 2)

Thus, knowing that the comparison algorithm is similar to ===, we can say that objects will be considered equal only if they have the same reference.

This is evidently not the case in your example, since you are creating the objects in the literal form, which creates a different reference to each object.

Therefore, even if some objects have the same properties with their respective equal values, the references shall not be the same and thus will not be removed since, for the language, they are different values.

This example illustrates this better. Note that only objects from same reference are removed. Note also, that even if a has the same "structure" as fakeA, This is not a factor for discrimination.

const a     = { id: 'a' };
const fakeA = { id: 'a' }; // Igual a `a`, mas com referência diferente.
const b     = { id: 'b' };

const mySet = new Set([a, a, a, fakeA, fakeA, fakeA, b, b, b]);

// Veja que somente trará 3 elementos:
console.log([...mySet]);

In your case, you can solve this by creating a simple algorithm that determines equality by property id. Thus, you can remove elements that have an equal ID. Something like this:

function removeDuplicateEntriesFromListByPropName(list, prop) {
  const map = Object.create(null);

  for (const item of list) {
    const id = item[prop];

    // Irá inserir no "mapa" somente elementos cujo o ID não estiver lá.
    if (!map[id]) {
      map[id] = item;
    }
  }

  // No final, retorne os valores do mapa:
  return Object.values(map);
}

const list = [
  { descricao: 'Multigases', id: 1 },
  { descricao: 'Iluminação Temporária', id: 3 },
  { descricao: 'Ventilação Temporária', id: 2 },
  { descricao: 'Capa de cobertura.', id: 21 },
  { descricao: 'Multigases', id: 1 },
  { descricao: 'Ventilação Temporária', id: 2 },
  { descricao: 'Cadeado', id: 85 }
];

console.log(removeDuplicateEntriesFromListByPropName(list, 'id'));

Browser other questions tagged

You are not signed in. Login or sign up in order to post.