一组集合(的集合...)

6

在Python中,可以通过frozenset来创建一组集合:

s, t = frozenset([1]), frozenset([1])
u = {s, t} # u == {frozenset([1])}

现在ECMAScript 6引入了Set对象,那么在JavaScript中有没有办法创建一个包含其他集合的唯一集合,即丢弃所有具有相同项的集合,只保留一个集合?
我问这个问题是因为以下代码不起作用:
var s = new Set([1]), t = new Set([1]);
var u = new Set([s, t]); // u == Set{Set{1}, Set{1}}

我理解Set可能会对其包含的其他集合的指针进行哈希处理,这就是为什么两个{1}看起来不同。我的问题是,是否有一种在JavaScript中实现上述Python行为的方法。


行为是正确的。集合st是不同的对象,因此它们应该是不同的。 - trincot
4
“我所询问的是,在JavaScript中是否有一种方法可以实现上述Python行为。” 不好意思,目前JavaScript没有定义对象相等性的方法。 - Felix Kling
@FelixKling 如果真是这样,请在下面发布您的答案,我会接受它。 - Ecir Hana
我猜你可以创建一个代理来捕获向集合添加项目的操作,并在要添加的项目与现有成员深度相等时跳过添加该项目。 - user663031
1个回答

2
这是因为在JavaScript中,只有同一个对象才被视为相等的对象值。例如,{} === {} 的结果是false
正如@torazaburo指出的那样,您可以为该集合创建一个代理,并拦截.add()调用,跳过与任何现有成员相等的项。您可以使用lodash库中的_.isEqual()函数来比较两个集合。
const firstSet = new Set([1])
     ,secondSet = new Set([1])

const newSet = new Set()

newSet.add = new Proxy(newSet.add, {
  apply: (target, thisArg, [value])=> {
    // Array.from() is required to use Array.prototype.some()
    if (!Array.from(newSet).some(element=> _.isEqual(element, value))) {
      target.call(newSet, value)
    }
    return target
  }
})

newSet.add(firstSet)
newSet.add(secondSet)

console.log(newSet.has(firstSet))  // logs true
console.log(newSet.has(secondSet)) // logs false, because secondSet 
                                   // has not been added, since it's a duplicate
console.log(newSet.size)           // logs 1

请查看JS Bin演示


2
我对JavaScript并不是很熟悉,但apply不是在O(n)中运行吗?我的意思是,这基本上是遍历所有已包含的集合,并在另一个O(n)中将每个集合与Array.isEqual进行比较。与使用数组有什么不同呢? - Ecir Hana
1
@EcirHana 你说得对,这和使用数组没有什么区别。 - Michał Perłakowski

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接