-
-
Save phillippelevidad/d44aef576dd9f97e046987302992dbf8 to your computer and use it in GitHub Desktop.
/** | |
* The UniquePropertySet class is designed to manage a collection of objects, | |
* ensuring that each object is unique based on its properties and values | |
* rather than its reference in memory. | |
* | |
* Beware, though, that this implementation is not optimized for performance, | |
* and that the JSON.stringify method does not handle non-serializable values | |
* consistently, such as functions, undefined, or circular references, which | |
* will cause objects containing such values to not be handled correctly. | |
*/ | |
class UniquePropertySet { | |
constructor() { | |
this.map = new Map(); | |
} | |
add(obj) { | |
const key = this._serialize(obj); | |
if (!this.map.has(key)) { | |
this.map.set(key, obj); | |
} | |
} | |
has(obj) { | |
const key = this._serialize(obj); | |
return this.map.has(key); | |
} | |
delete(obj) { | |
const key = this._serialize(obj); | |
return this.map.delete(key); | |
} | |
_serialize(obj) { | |
// Sort the object's keys to ensure consistent order | |
return JSON.stringify(obj, Object.keys(obj).sort()); | |
} | |
clear() { | |
return this.map.clear(); | |
} | |
get size() { | |
return this.map.size; | |
} | |
values() { | |
return this.map.values(); | |
} | |
*[Symbol.iterator]() { | |
for (let value of this.map.values()) yield value; | |
} | |
} | |
// Usage | |
const assert = require("assert"); | |
const uniqueObjects = new UniquePropertySet(); | |
uniqueObjects.add({ a: 1, b: 2 }); | |
uniqueObjects.add({ b: 2, a: 1 }); // Won't be added, as it's considered a duplicate | |
assert.strictEqual(uniqueObjects.size, 1); | |
uniqueObjects.add({ a: 1, b: 2, c: 3 }); // Will be added, as it's a different object | |
assert.strictEqual(uniqueObjects.size, 2); | |
uniqueObjects.delete({ a: 1, b: 2 }); // Correctly deletes the first entry | |
assert.strictEqual(uniqueObjects.size, 1); | |
// Nested objects are supported too | |
uniqueObjects.clear(); | |
uniqueObjects.add({ a: 1, b: { c: 2 } }); | |
uniqueObjects.add({ a: 1, b: { c: 2 } }); | |
assert.strictEqual(uniqueObjects.size, 1); | |
// Even nested objects are supported | |
uniqueObjects.clear(); | |
uniqueObjects.add({ a: 1, b: { d: 3, c: 2 } }); | |
uniqueObjects.add({ a: 1, b: { c: 2, d: 3 } }); | |
assert.strictEqual(uniqueObjects.size, 1); |
você deixou esse comentário lá (https://gist.github.com/phillippelevidad/d44aef576dd9f97e046987302992dbf8 ), e tinha falado sobre o problema de performance, dai so comentei para tirar a minha duvida se com for..of o algoritmo ficaria +performático e que sou meio iniciante e ñ entendo mt sobre essas qst (desconsidere se falei alguma besteira)
Vi meu comentário na aula de Set e WeakSet. Lá eu falei que essa solução que eu botei aqui no Gist tem um problema inerente de performance porque usa JSON.stringify. Daí, se eu entendi bem a sua dúvida aqui, é porque você está curioso se fazer um for..of resolveria, ou seja, se seria mais rápido.
Em tese, sim :) mas só tem um jeito da gente saber, e é fazendo um benchmark. O Erick ensina isso mais à frente no curso, mas bora rodar um benchmark aqui rapidão e ver o que acontece.
Rodei o código abaixo 3 vezes, pra gente ter uma análise melhor de 3, e olha só os tempos:
deepEqual x 941,275 ops/sec ±2.13% (85 runs sampled)
JSON.stringify x 94,887 ops/sec ±1.91% (88 runs sampled)
Fastest is deepEqual
deepEqual x 921,202 ops/sec ±2.98% (82 runs sampled)
JSON.stringify x 91,463 ops/sec ±1.53% (84 runs sampled)
Fastest is deepEqual
deepEqual x 944,692 ops/sec ±1.74% (85 runs sampled)
JSON.stringify x 88,985 ops/sec ±2.92% (77 runs sampled)
Fastest is deepEqual
Você pode ver que, no último teste, o deepEqual rodou 944.692 por segundo, contra apenas 88.985 do JSON.stringify. E os outros dois testes não ficam muito diferentes, então podemos que, na média, o deepEqual que mandei pra você no comentário acima é 10x mais rápido que o JSON.stringify!
Segue o código do teste, usando a lib https://www.npmjs.com/package/benchmark. Eu crio dois objetos idênticos e deixo rodar a comparação nas duas formas que estamos testando.
const deepEqual = require("./deepEqual.js");
const Benchmark = require("benchmark");
const obj1 = {
firstName: "John",
lastName: "Doe",
dateOfBirth: new Date("1980-01-01"),
address: {
street: "North Pole",
city: "Arctic Circle",
country: "Earth",
},
orders: [
{
product: {
name: "iPhone",
price: 699,
},
quantity: 1,
},
{
product: {
name: "MacBook Pro",
price: 1299,
},
quantity: 2,
},
],
};
const obj2 = {
firstName: "John",
lastName: "Doe",
dateOfBirth: new Date("1980-01-01"),
address: {
street: "North Pole",
city: "Arctic Circle",
country: "Earth",
},
orders: [
{
product: {
name: "iPhone",
price: 699,
},
quantity: 1,
},
{
product: {
name: "MacBook Pro",
price: 1299,
},
quantity: 2,
},
],
};
const suite = new Benchmark.Suite();
suite
// add tests
.add("deepEqual", function () {
return deepEqual(obj1, obj2);
})
.add("JSON.stringify", function () {
return JSON.stringify(obj1) === JSON.stringify(obj2);
})
// add listeners
.on("cycle", function (event) {
console.log(String(event.target));
})
.on("complete", function () {
console.log("Fastest is " + this.filter("fastest").map("name"));
})
// run async
.run({ async: true });
Massa, né :)
Opa, iae blz? era isso msm "Daí, se eu entendi bem a sua dúvida aqui, é porque você está curioso se fazer um for..of resolveria, ou seja, se seria mais rápido" eu ainda ñ chegai nesse módulo ainda "benchmark" msm valeuzão pela resposta...
Opa, blz e ai? foi da aula de Set e WeakSet no módulo de advanced js data types! obg por ter respondido a minha dúvida... deveria ter replicado por lá o comentário, porém a plataforma n permite...