【问题标题】:Does JavaScript have an implementation of a set data structure?JavaScript 是否有一个集合数据结构的实现?
【发布时间】:2011-02-01 04:18:51
【问题描述】:

我正在寻找一个用 JavaScript 实现的集合数据结构的体面实现。它应该能够支持纯 JavaScript 对象的元素。

目前我只找到Closure Library's structs.Set,但我不喜欢它修改我的数据的事实。

【问题讨论】:

标签: javascript data-structures set


【解决方案1】:

您可以围绕我的jshashtable 提供的哈希表的键构建一个简单的包装器。我在某个地方敲了一个,稍后我会挖出来。

更新

我已经完成并测试了 HashSet 的实现,并将其上传到 GitHub 上的 jshashtable 项目。你可以download itview the source

var s = new HashSet();
var o1 = {name: "One"}, o2 = {name: "Two"};
s.add(o1);
s.add(o2);
s.values(); // Array containing o1 and o2

【讨论】:

  • 您能解释一下您的库是如何计算对象哈希码的吗?
  • 它在文档中,但总而言之:哈希码是字符串,您可以向Hashtable构造函数提供计算哈希码的函数(以及比较两个对象和决定它们是否相等)。否则,它会在键上查找名为hashCode() 的方法。作为最后的手段,它尝试使用toString()String() 将密钥转换为字符串。如果您的所有键都哈希到相同的值(例如“[object Object]”),因为您没有使用上述任何机制,那么它们都会进入同一个存储桶,并且必须使用您的简单线性搜索。
  • 嗨,蒂姆,这个库是否会在集合中存储以下格式:var o1 = {firstname: "John", lastname: "Doe"}, o2 = {firstname: "Eric", lastname: "Lencher"};
【解决方案2】:

我认为除了将其存储在对象本身之外,没有其他方法可以使用对象的哈希码。严格来说,可以使用简单的线性搜索来创建不使用散列的集合类,但这几乎没有效率。

【讨论】:

  • 确实如此。除了与其他所有对象进行比较之外,没有办法在 JS 中获取对象的标识。
【解决方案3】:

我喜欢Simple-JS-Set(可能是因为我写的)。它支持任何类型的 JavaScript 对象。它具有以下 API:

  • Set(hashFunction):(构造函数)使用给定的 hashFunction 实例化一个新集合(默认为 JSON.stringify
  • add(item): 将一个项目添加到集合中
  • remove(item):从集合中移除一个项目
  • contains(item): 返回该项目是否包含在集合中
  • size():返回集合中唯一项的数量
  • each(function(item), thisObj):在thisObj 的上下文中对集合中的每个项目执行一个函数

【讨论】:

    【解决方案4】:

    ECMAScript 6 有它

    规格:http://www.ecma-international.org/ecma-262/6.0/#sec-set-constructor

    用法:https://github.com/lukehoban/es6features#map--set--weakmap--weakset

    例子:

    var s = new Set()
    s.add("hello").add("goodbye").add("hello")
    s.size === 2
    s.has("hello") === true
    

    为不支持的浏览器实现它的模块:https://github.com/medikoo/es6-set

    【讨论】:

    • 这不适用于 JS 对象。对象被保留作为参考。具有相同属性值的对象将被视为两个对象并添加到 Set 中。
    【解决方案5】:

    使用the ECMAScript 2015 (ES6) standard Set Data structure真的好用:

    var mySet = new Set();
    
    mySet.add(1);
    mySet.add(5);
    mySet.add("some text");
    var o = {a: 1, b: 2};
    mySet.add(o);
    
    mySet.has(1); // true
    mySet.has(3); // false, 3 has not been added to the set
    mySet.has(5);              // true
    mySet.has(Math.sqrt(25));  // true
    mySet.has("Some Text".toLowerCase()); // true
    mySet.has(o); // true
    
    mySet.size; // 4
    
    mySet.delete(5); // removes 5 from the set
    mySet.has(5);    // false, 5 has been removed
    
    mySet.size; // 3, we just removed one value
    

    使用 AngularJs 的更新

    请注意,集合不适用于 ng-repeat。所以最好使用数组并应用唯一的过滤器

    【讨论】:

      【解决方案6】:

      在 ES6 版本的 Javascript 中,您已经为 set (check compatibility with your browser) 构建了类型。

      var numbers = new Set([1, 2, 4]); // Set {1, 2, 4}
      

      添加一个元素到集合中,您只需使用.add(),它在O(1) 中运行,或者将元素添加到集合(如果它不存在)或不执行任何操作已经在那了。您可以在那里添加任何类型的元素(数组、字符串、数字)

      numbers.add(4); // Set {1, 2, 4}
      numbers.add(6); // Set {1, 2, 4, 6}
      

      检查集合中的元素数量,您可以简单地使用.size。也运行在O(1)

      numbers.size; // 4
      

      从集合中删除元素,请使用.delete()。如果值存在(并且已被删除)则返回 true,如果值不存在则返回 false。也在O(1) 中运行。

      numbers.delete(2); // true
      numbers.delete(2); // false
      

      检查元素是否存在在集合中使用.has(),如果元素在集合中则返回true,否则返回false。也在O(1) 中运行。

      numbers.has(3); // false
      numbers.has(1); // true
      

      除了你想要的方法,还有几个:

      • numbers.clear(); 只会删除集合中的所有元素
      • numbers.forEach(callback); 按插入顺序迭代集合的值
      • numbers.entries(); 创建所有值的迭代器
      • numbers.keys(); 返回与 numbers.values() 相同的集合的键

      还有一个 Weakset,它只允许添加对象类型的值。

      【讨论】:

      • 你确定,在 Set 中的插入在 O(1) 中运行吗?我找不到像这样的任何实现,并且我发现它的运行时间为 O(N),并且该实现具有 indexOf 方法,该方法检查该值是否存在于数组中。我需要在循环中使用它,因此我对使用 indexOf 方法犹豫不决。您能否指出任何实现或您阅读的资源?
      • @Vatsal 是的,将元素插入集合需要 O(1) 分摊时间。我不知道在哪里可以找到 JS 中的集合实现,但是数据结构中的每一本基础书籍都会证实这一点。 IndexOf 是一种对数组进行操作的方法,因此它花费 O(n) 时间也就不足为奇了。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-05-28
      • 2010-12-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-22
      • 2021-12-13
      相关资源
      最近更新 更多