Arrays ruby中Set的优点

Arrays ruby中Set的优点,arrays,ruby,hash,set,Arrays,Ruby,Hash,Set,Set的主要优点似乎是维护独特的元素。但这可以在数组中轻松实现 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 由于数组具有与之相关的各种功能和操作,因此何时以及为什么要使用设置 有很多

Set
的主要优点似乎是维护独特的元素。但这可以在
数组中轻松实现

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
,但我还没有遇到
Set
的重要应用当然,无论你用
Set
做什么,都有一种方法可以用
Array
来做。使用
集合
的优点是,由于它是基于
散列
实现的,因此对它的大多数操作都是O(1)复杂度,而使用
数组
进行操作可以是O(n)

例如:

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

从技术上讲,使用Ruby
数组和
集合可以获得相同的结果。但是,Ruby的
模块和
类也是如此。变量和方法可以同时存在,但它们的用途不同,当其他人阅读代码时,他/她将在不试图理解您的设计决策的情况下获得这一意义

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

其次,当您执行诸如
.subset?
.superset?
.intersect?
等操作时,使用集合时,您的代码更具可读性。新加入的用户可能会猜测
数组
操作的功能,但使用集合时,它们都在那里。查看哪一个更具可读性:

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

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

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

阵列
  • 可以有重复的元素
  • 维持秩序
  • 可以按顺序进行迭代
  • 搜索元素很慢,追加元素和从位置获取元素很快
  • 保持元素的唯一性很慢
设置
  • 不能有重复的元素
  • 没有排序(理论背景:)
  • 查找元素存在的速度快,追加元素的速度快
  • 独特性来自设计
集合实际上取自数学概念:

Ruby集合内部使用哈希进行存储,如文档中所述:

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

元素的相等性是根据对象#eql?和 对象#散列。Set假定每个元素的标识不存在 在存储时进行更改。修改集合中的元素将呈现 服务器设置为不可靠状态。当要存储字符串时 将存储字符串的冻结副本,除非原始字符串 已经冻结了

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

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


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

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

有足够的理由在可能的情况下使用
Set
Hash

这是一个广泛的问题,观点对其有很强的定义。正如您已经说过的,这完全取决于用例。事实上,您发现集合的用例很少,这并不意味着所有的集合都是一样的。我对编程和ruby是新手。当我提到“很少使用案例”时,我的意思只是我没有暴露。我希望通过了解其他人是如何实现(应用)集合的,从而更好地理解集合及其应用。谢谢,我明白,普拉善。别把它当回事。我的意思是,这是非常个人化的,不容易推广。如果有a)一个证明链接和b)更具体的“大多数”操作列表,那就太好了。由于动态调整大小,应该分摊O(1)复杂性。太棒了。谢谢分享