为什么Javascript Set不能做独特的对象?

Mat*_*ake 13 javascript

集合应该包含唯一对象,但它不适用于javascript中的对象.

var set = new Set()
<- undefined
set.add({name:'a', value: 'b'})
<- Set {Object {name: "a", value: "b"}}
set.add({name:'a', value: 'b'})
<- Set {Object {name: "a", value: "b"}, Object {name: "a", value: "b"}}
Run Code Online (Sandbox Code Playgroud)

它适用于基元

var b = new Set()
<- undefined
b.add(1)
<- Set {1}
b.add(2)
<- Set {1, 2}
b.add(1)
<- Set {1, 2}
Run Code Online (Sandbox Code Playgroud)

那么如何让它与对象一起工作呢?我得到的事实是,它们是具有相同值的不同对象,但我正在寻找像一个深刻的独特集合.

编辑:

这就是我实际在做的事情

    var m = await(M.find({c: cID}).populate('p')) //database call
    var p = new Set();
    m.forEach(function(sm){
        p.add(sm.p)
    })
Run Code Online (Sandbox Code Playgroud)

这是为了获得一个独特的sm.p列表

小智 11

根据 Joe Yichong 的帖子,这里提出了扩展 TypeScript Set 的建议。

export class DeepSet extends Set {

  add (o: any) {
    for (let i of this)
      if (this.deepCompare(o, i))
        return this;
    super.add.call(this, o);
    return this;
  };

  private deepCompare(o: any, i: any) {
    return JSON.stringify(o) === JSON.stringify(i)
  }
}

Run Code Online (Sandbox Code Playgroud)

  • 但这缺少使用集合的要点:O(1) 的加法运算。相反,这必须将每个新条目与每个先前条目进行比较。 (8认同)

Cau*_*wer 10

另一种选择是您可以使用 JSON.stringify() 来保持对象的唯一性,这样它就可以与字符串而不是对象引用进行比较。

        set.add(JSON.stringify({name:'a', value: 'b'}))
Run Code Online (Sandbox Code Playgroud)

然后在格式化所有内容后,您可以将这些行解析回数组,例如

    const formattedSet = [...set].map(item) => {
      if (typeof item === 'string') return JSON.parse(item);
      else if (typeof item === 'object') return item;
    });
Run Code Online (Sandbox Code Playgroud)

  • 像这样的解决方案需要考虑顺序。不能相信 JSON.stringify() 每次都会以相同的顺序给出键的结果。除此之外,还有许多值无法正确字符串化,例如 Infinity、NaN 和递归对象。 (3认同)

Joe*_*ong 9

好吧,如果您正在寻找深层的唯一集合,则可以通过扩展原始的“集合”来自己制作深层集合,如下所示:

function DeepSet() {
    //
}
DeepSet.prototype = Object.create(Set.prototype);
DeepSet.prototype.constructor = DeepSet;
DeepSet.prototype.add = function(o) {
    for (let i of this)
        if (deepCompare(o, i))
            throw "Already existed";
    Set.prototype.add.call(this, o);
};
Run Code Online (Sandbox Code Playgroud)

  • 这是一个非常糟糕的主意。您还需要覆盖 has、delete 和 add。此外,它现在将在 Omega(n) 中运行。 (5认同)
  • 这是添加此行为的好方法。不幸的是,没有原生的“ deepCompare”方法。 (2认同)
  • 当然。`DeepSet` 必须由我们自己实现,就像我们必须自己实现 `deepCompare` 方法一样。 (2认同)

小智 -6

这是天真的,我确信有更好的方法来获取唯一数据(例如使数据库查询返回唯一数据,但这取决于数据库),但是您可以检查该对象是否已经在之前的集合中插入它。

var m = await(M.find({c: cID}).populate('p')) //database call
var p = new Set();
m.forEach(function(sm){
    if(!p.has(sm.p)) p.add(sm.p)
})
Run Code Online (Sandbox Code Playgroud)

  • 有点违背了使用集合的目的,也可以只使用数组。 (12认同)
  • 该评论应该为-1。如果您要检查它是否存在于 0(n) 处,那么使用 Set 就没有意义。另外,这并不“天真”,我有一个 React 应用程序,其中使用像 Set 这样的数据结构(如果我们可以像 Java 或 C# 那样以正确的方式实现它)将是我的最佳选择。 (6认同)