【问题标题】:Advantages of Set in rubyRuby中Set的优点
【发布时间】:2016-04-11 12:38:30
【问题描述】:

Set 的主要优势似乎在于保持独特的元素。但这可以在Array 中轻松实现,

array = [2,3,4]
array | [2,5,6] # => [2,3,4,5,6]

我遇到的唯一独特的功能(可能适用于少数用例)是,

set1 = [1,2,3].to_set
set2 = [2,1,3].to_set
set1 == set2 # => true
[1,2,3] == [2,1,3] # => false

由于Array 具有与之相关的各种功能和操作,我何时以及为什么应该使用Set

有很多链接可以比较ArraySet,但我没有遇到Set 的重要应用。

【问题讨论】:

  • 这是一个广泛的问题,并由意见强烈定义。正如您已经说过的,这完全取决于用例。您发现集合的用例很少这一事实并不意味着这对所有人都是一样的。
  • 我是编程和 ruby​​ 的新手。当我提到“少数用例”时,我只是指我缺乏曝光率。我希望通过查看其他人如何实现(应用)它来更好地理解集合及其应用。谢谢。
  • 我明白了,普拉桑斯。不要个人认为。我只是说这是非常个人化的,不能轻易概括。

标签: arrays ruby hash set


【解决方案1】:

当然,无论您可以使用Set 做什么,都可以使用Array 进行操作。使用Set 的好处是,由于它是基于Hash 实现的,因此对其进行的大多数操作都是O(1) 复杂度,而使用Array 进行操作可能是O(n)。

例如:

Set.new([1, 2, 3]).include?(2) # O(1) complexity
[1, 2, 3].include?(2) # O(n) complexity

【讨论】:

  • 如果有 a) 证明链接和 b) 更具体的“大多数”操作列表,那就太好了。
  • 由于动态调整大小,应该摊销 O(1) 复杂度。
【解决方案2】:

这两个类定义了不同的数据结构:

数组

  • 可以有重复的元素
  • 维护订单
  • 可以按顺序迭代
  • 搜索元素很慢,添加元素和从位置获取元素很快
  • 保持元素的唯一性很慢

套装

集合实际上取自数学概念:https://en.wikipedia.org/wiki/Set_(mathematics)

如文档中所述,在 Ruby set 内部使用散列进行存储:

Set使用Hash作为存储,所以一定要注意以下几点:

元素的相等性是根据 Object#eql?和 对象#hash。 Set 假设每个元素的身份不 存储时更改。修改集合的元素将呈现 设置为不可靠状态。当要存储一个字符串时,一个 除非原始字符串,否则将存储字符串的冻结副本 已经冻结了。

当您查看代码时,它在内部存储为哈希,其中用户给定的对象作为键,布尔值作为值(准确地说:添加对象时为真)。

为什么要使用集合?如果您想强制执行唯一性并且不需要任何排序 - 集合是您的最佳选择。当您并不真正关心唯一性并且排序很重要时 - 数组是您的选择。

否则 - 您需要任意决定;)

【讨论】:

    【解决方案3】:

    出于显而易见的原因,请参阅此处的其他答案。 出于性能原因,请查看 MRI Ruby 1.9.3 中这个小基准测试的结果:

    require 'benchmark' 
    require 'set' 
    
    array = (1..100000).to_a 
    set = array.to_set 
    #hash = Hash[array.map {|x| [x, nil]}] #beter voor heel grote volumes mar trager
    hash = Hash[*array]
    
    Benchmark.bmbm do |x| 
      x.report("Set.include?")   { 10000.times { set.include?(99999) } }
      x.report("Array.include?") { 10000.times { array.include?(99999) } } 
      x.report("Hash.include?")  { 10000.times { hash.include?(99999) } } 
    end 
    

    给了

    Rehearsal --------------------------------------------------
    Set.include?     0.000000   0.000000   0.000000 (  0.015604)
    Array.include?  37.940000   0.000000  37.940000 ( 38.651992)
    Hash.include?    0.000000   0.000000   0.000000 (  0.001000)
    ---------------------------------------- total: 37.940000sec
    
                         user     system      total        real
    Set.include?     0.000000   0.000000   0.000000 (  0.002001)
    Array.include?  38.157000   0.000000  38.157000 ( 38.730615)
    Hash.include?    0.000000   0.000000   0.000000 (  0.001001)
    

    有足够的理由尽可能使用SetHash

    【讨论】:

    • 太棒了。感谢分享
    【解决方案4】:

    好吧,从技术上讲,您可以使用 Ruby ArraysSets 获得相同的结果。但是,Ruby 的ModulesClasses 也是如此。您可以在两者中使用变量和方法,但它们用于不同的目的,当其他人阅读代码时,他/她将理解该含义,而无需尝试弄清楚您的设计决策。

    我猜SetsArrays 的情况是一样的。您可以使用数组实现相同的结果,但使用集合您的变量传达有关您的业务逻辑的附加信息(内容必须是唯一的)。基本上,它们是不同的数据结构。我们有不同的数据结构是有原因的。

    其次,当你执行.subset?.superset?.intersect? 等操作时,使用集合你的代码更具可读性。新来的人会猜测array | array 操作的作用,但使用集合是都在那里。看看哪个更具可读性:

    ([1, 2, 3] & [2, 3]).empty?          # => false
    Set[1, 2, 3].intersect? Set[2, 3]    # => true
    

    第三,与集合的交集操作可能预先优化并且可能运行得更快。

    【讨论】:

      猜你喜欢
      • 2016-07-12
      • 2012-09-27
      • 2018-12-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-22
      • 1970-01-01
      相关资源
      最近更新 更多