设置在红宝石中的优点

问题描述 投票:10回答:4

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 set
4个回答
10
投票

当然,无论你用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

7
投票

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

Arrays

  • 可以有重复的元素
  • 维持订单
  • 可以按顺序迭代
  • 搜索元素很慢,附加元素并从位置获取元素很快
  • 保持元素的独特性很慢

Sets

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

在Ruby内部设置使用哈希存储,如文档中所述:

Set使用Hash作为存储,因此您必须注意以下几点:

元素的相等性是根据Object#eql确定的?和Object #hash。 Set假定每个元素的标识在存储时不会更改。修改集合的元素会将集合呈现为不可靠状态。当要存储字符串时,将存储字符串的冻结副本,除非原始字符串已被冻结。

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

为什么要使用套装?如果您想要强制执行唯一性而且您不需要任何订购 - 套装是您的最佳选择。当您不关心唯一性并且订购很重要时 - Array是您的选择。

否则 - 你需要仲裁决定;)


4
投票

由于显而易见的原因,请在此处查看其他答案。出于性能原因,请参阅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


1
投票

好吧,从技术上讲,你可以使用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

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

© www.soinside.com 2019 - 2024. All rights reserved.