`
nj0308
  • 浏览: 4506 次
  • 性别: Icon_minigender_1
  • 来自: 成都
文章分类
社区版块
存档分类
最新评论

个人感觉关于Set类的两个缺陷

阅读更多
1、map(collect) 和 map!(collect!) 方法返回类型不一致
   map返回的是Array,而map!返回的是Set。
   当然,这是小缺陷。

2、如果Set的元素也是Set类型,并不会对比较为true的多个元素进行合并
s1 = Set.new [1, 2]   => #<Set: {1, 2}>
s2 = Set.new [1, 2]   => #<Set: {1, 2}>
s1 == s2              => true
s = Set.new           => #<Set: {}>
s << s1               => #<Set: {#<Set: {1, 2}>}>
s << s2               => #<Set: {#<Set: {1, 2}>, #<Set: {1, 2}>}>


个人感觉第2个缺陷比较严重(我每次都得把元素转换成Array)。
分享到:
评论
14 楼 jhsea3do 2009-08-10  
就是hash的问题了

ruby 1.8.5
irb(main):019:0> s.hash
=> -605831918
irb(main):020:0> s1.hash
=> -605820668
irb(main):021:0> s2.hash
=> -605827148

ruby 1.8.7
irb(main):010:0> s.hash
=> 25
irb(main):011:0> s1.hash
=> 14
irb(main):012:0> s2.hash
=> 14
13 楼 rainchen 2009-08-08  
是ruby 1.8.6的bug,我系统中有两个版本ruby,测试结果如下:
ubuntu:~$ ruby -v
ruby 1.8.7 (2008-08-11 patchlevel 72) [i486-linux]
ubuntu:~$ irb -v
irb 0.9.5(05/04/13)
ubuntu:~$ irb
irb(main):001:0> require 'set'
=> true
irb(main):002:0> s1 = Set.new [1,2]
=> #<Set: {1, 2}>
irb(main):003:0> s2 = Set.new [1,2]
=> #<Set: {1, 2}>
irb(main):004:0> s1 == s2
=> true
irb(main):005:0> s = Set.new
=> #<Set: {}>
irb(main):006:0> s << s1
=> #<Set: {#<Set: {1, 2}>}>
irb(main):007:0> s << s2
=> #<Set: {#<Set: {1, 2}>}>
irb(main):010:0> exit

ubuntu:~$ sudo switch_ruby 
current = ruby 1.8.7 (2008-08-11 patchlevel 72) [i486-linux]

Select Option

1. ruby-1.8.6-p368
2. ruby-1.8.7-p72
3. ruby-1.8.7-p160
4. ruby-1.9.1-p0
5. exit

 Your choice? : 1
Current ruby version is :
ruby 1.8.6 (2009-03-31 patchlevel 368) [i686-linux]
ubuntu:~$ ruby -v
ruby 1.8.6 (2009-03-31 patchlevel 368) [i686-linux]
ubuntu:~$ irb -v
irb 0.9.5(05/04/13)
ubuntu:~$ irb
irb(main):002:0> require 'set'
=> true
irb(main):003:0> s1 = Set.new [1,2]
=> #<Set: {1, 2}>
irb(main):004:0> s2 = Set.new [1,2]
=> #<Set: {1, 2}>
irb(main):005:0> s1 == s2
=> true
irb(main):006:0> s = Set.new
=> #<Set: {}>
irb(main):007:0> s << s1
=> #<Set: {#<Set: {1, 2}>}>
irb(main):008:0> s << s2
=> #<Set: {#<Set: {1, 2}>, #<Set: {1, 2}>}>


12 楼 qianjigui 2009-08-07  
<div class="quote_title">nj0308 写道</div>
<div class="quote_div">看来确实是个缺陷,1.8.7版本已经将其修正了。</div>
<pre name="code" class="ruby">xxx@xxxx-laptop:~$ ruby -v
ruby 1.8.7 (2009-06-12 patchlevel 174) [i686-linux]
xxx@xxxx-laptop:~$ irb -v
irb 0.9.5(05/04/13)
xxx@xxxx-laptop:~$ irb
irb(main):001:0&gt; require 'set'
=&gt; true
irb(main):002:0&gt; s1 = Set.new [1,2]
=&gt; #&lt;Set: {1, 2}&gt;
irb(main):003:0&gt; s2 = Set.new [1,2]
=&gt; #&lt;Set: {1, 2}&gt;
irb(main):004:0&gt; s1==s2
=&gt; true
irb(main):005:0&gt; s = Set.new
=&gt; #&lt;Set: {}&gt;
irb(main):006:0&gt; s&lt;&lt;s1
=&gt; #&lt;Set: {#&lt;Set: {1, 2}&gt;}&gt;
irb(main):007:0&gt; s&lt;&lt;s2
=&gt; #&lt;Set: {#&lt;Set: {1, 2}&gt;}&gt;</pre>
 
<p>以上是测试结果。</p>
11 楼 asialee 2009-08-07  
大家都讨论这么高深了,我起初还因为是java呢,原来是ruby,唉,落伍了。
10 楼 nj0308 2009-08-07  
看来确实是个缺陷,1.8.7版本已经将其修正了。
9 楼 Hooopo 2009-08-07  
nj0308 写道
Hooopo 写道


这说明set在判断是否相等与是不是同一个对象无关。

而是和对象的hash值有关。其实就是==和eql?的区别。



我只是不明白两个元素相同的Set为什么不eql? 有什么更深的含义吗?

引用
   Equality---At the +Object+ level, +==+ returns +true+ only if _obj_
   and _other_ are the same object. Typically, this method is
   overridden in descendent classes to provide class-specific meaning.

   Unlike +==+, the +equal?+ method should never be overridden by
   subclasses: it is used to determine object identity (that is,
   +a.equal?(b)+ iff +a+ is the same object as +b+).

   The +eql?+ method returns +true+ if _obj_ and _anObject_ have the
   same value. Used by +Hash+ to test members for equality. For
   objects of class +Object+, +eql?+ is synonymous with +==+.
   Subclasses normally continue this tradition, but there are
   exceptions. +Numeric+ types, for example, perform type conversion
   across +==+, but not across +eql?+, so:


我的是1.8.6.....
8 楼 QuakeWang 2009-08-07  
---看错的分割线---
发现add是<<别名

在我机器上测试 << 是正常的:
ruby -v
ruby 1.8.7 (2009-04-08 patchlevel 160) [i686-linux]
7 楼 Hooopo 2009-08-07  
QuakeWang 写道
用s的add方法,不要用<<方法
s1 = Set.new [1, 2]   => #<Set: {1, 2}>
s2 = Set.new [1, 2]   => #<Set: {1, 2}>
s1 == s2              => true
s = Set.new           => #<Set: {}>
s.add s1               => #<Set: {#<Set: {1, 2}>}>
s.add s2               => #<Set: {#<Set: {1, 2}>}>

咦?你用的是那个版本的?add就是<<的意思。。怎么会不一样呢?
引用
# Adds the given object to the set and returns self.  Use +merge+ to
  # add several elements at once.
  def add(o)
    @hash[o] = true
    self
  end
  alias << add


6 楼 Hooopo 2009-08-07  
看了一下set的源代码,其实想要改变第二种情况也不难,hack了一下:

require 'set'


class Set
  def hash
    @hash.keys.hash
  end
 def eql?(o)
    return false unless o.is_a?(Set)
    @hash == (o.instance_eval{@hash})
  end
end

s1 = Set.new [1, 2]    #<Set: {1, 2}>
s2 = Set.new [1, 2]    #<Set: {1, 2}>
p s1 == s2             # true
s = Set.new            #<Set: {}>
s << s1                #<Set: {#<Set: {1, 2}>}>
s << s2                #<Set: {#<Set: {1, 2}>}>
p s



5 楼 QuakeWang 2009-08-07  
用s的add方法,不要用<<方法
s1 = Set.new [1, 2]   => #<Set: {1, 2}>
s2 = Set.new [1, 2]   => #<Set: {1, 2}>
s1 == s2              => true
s = Set.new           => #<Set: {}>
s.add s1               => #<Set: {#<Set: {1, 2}>}>
s.add s2               => #<Set: {#<Set: {1, 2}>}>


---看错的分割线---
发现add是<<别名

在我机器上测试 << 是正常的:
ruby -v
ruby 1.8.7 (2009-04-08 patchlevel 160) [i686-linux]
4 楼 nj0308 2009-08-07  
Hooopo 写道


这说明set在判断是否相等与是不是同一个对象无关。

而是和对象的hash值有关。其实就是==和eql?的区别。



我只是不明白两个元素相同的Set为什么不eql? 有什么更深的含义吗?
3 楼 nj0308 2009-08-07  
chenk85 写道
1) Set 的 map!() 方法是collect!()的别名,map() 方法是来自于Enumerable的,所以语义不同。

我也清楚Set并没有对map进行重新定义,只是感觉不是很舒服。


chenk85 写道
2) 在你的代码中,s1和s2是不同第两个对象,你可以输出它们的对象id(object_id)看看。如果你对此不满意可以重写Set的<<方法。

s1和s2是两个对象不错,但Set的合并并不是说一定要同一个对象,将s1和s2改成Array看看

a1 = [1,2]             => [1, 2]
a2 = [1,2]             => [1, 2]
a1.object_id           => 50414640
a2.object_id           => 50402440
sss = Set.new          => #<Set: {}>
sss << a1              => #<Set: {[1, 2]}>
sss << a2              => #<Set: {[1, 2]}>



2 楼 Hooopo 2009-08-07  
chenk85 写道
1) Set 的 map!() 方法是collect!()的别名,map() 方法是来自于Enumerable的,所以语义不同。

2) 在你的代码中,s1和s2是不同第两个对象,你可以输出它们的对象id(object_id)看看。如果你对此不满意可以重写Set的<<方法。

不同的两个对象是可以合并的,只要他们的hash值相等...
看这个例子:
irb(main):023:0> s1 = String.new
=> ""
irb(main):024:0> s2 = String.new
=> ""
irb(main):025:0> s1.object_id
=> 23576640
irb(main):026:0> s2.object_id
=> 23571930
irb(main):027:0> s1.hash
=> 0
irb(main):028:0> s2.hash
=> 0
irb(main):029:0> set = Set.new
=> #<Set: {}>
irb(main):030:0> set << s1
=> #<Set: {""}>
irb(main):031:0> set << s2
=> #<Set: {""}>
irb(main):032:0>



这说明set在判断是否相等与是不是同一个对象无关。

而是和对象的hash值有关。其实就是==和eql?的区别。

1 楼 chenk85 2009-08-07  
1) Set 的 map!() 方法是collect!()的别名,map() 方法是来自于Enumerable的,所以语义不同。

2) 在你的代码中,s1和s2是不同第两个对象,你可以输出它们的对象id(object_id)看看。如果你对此不满意可以重写Set的<<方法。

相关推荐

    java代码缺陷自动分析工具之FindBugs介绍.pdf

    FindBugs 可以检测 equals() 和 hashCode() 方法的实现相关问题,这两个方法非常重要,因为几乎所有基于集合的类(如 List、Map、Set 等)都调用它们。 2. 检测忽略方法返回值 FindBugs 可以检测代码中忽略了不应该...

    Java并发缺陷模式1

    除了这两个例子,还有其他四个鲜为人知的并发缺陷模式,尽管未在文章中详细列出,但通常包括以下几点: 3. 不正确的线程同步:当使用`synchronized`关键字时,确保同步的粒度适中,过大可能导致不必要的阻塞,过小...

    毕设项目:基于QT+yolov5s的缺陷检测系统,包括图像检测以及目标检测两个部分.zip

    QObject::setProperty()函数可以在运行时为类定义一个新的属性,称之为动态属性。动态属性是针对类的实例定义的。 动态属性可以使用QObject::property()查询,就如在类定义里用Q_PROPERTY宏定义的属性一样。 例如...

    基于RBF神经网络的储油罐底板缺陷量化方法.pdf

    通过对这些数据的分析,研究者发现了磁异常幅值和占宽这两个特征量与缺陷尺寸及角度的关联性。这些特征量被用作输入,以训练RBF神经网络。 接下来,模拟退火算法被引入,这是一种全局优化方法,能够避免在复杂的...

    MyEclipse Date类练习

    这两个类在MyEclipse环境中经常被用于进行日期和时间的计算与管理。以下是对这两个类的详细说明以及如何在MyEclipse中进行实践练习。 `Date`类是Java.util包中的一个核心类,它代表了特定的瞬间,精确到毫秒。`Date...

    Java高级特性 第一章 集合框架和泛型

    Iterator接口提供了两个方法:hasNext()和next(),用于判断是否存在下一个可访问的元素和返回要访问的下一个元素。 Map接口 Map接口是一个键值对的集合,可以存储一组键值对的对象,提供了key到value的映射,通过...

    船舶电子海图系统常见缺陷(JRC设备).docx

    【船舶电子海图系统常见缺陷】(JRC设备) 船舶电子海图系统(Electronic Chart Display and Information System, ECDIS)是现代航海中的关键技术,它替代了传统的纸质海图,提高了航行的安全性和效率。然而,操作不当...

    Physical Metallurgy, Fifth Edition 3-Volume Set (Volume 1

    但从这个描述我们可以推断出这是一套关于物理冶金学的专业书籍,包含了最新的研究成果和技术进展。 #### 标签解析:“Physic asm” 这里的标签可能存在输入错误,“Physic asm”可能是指“Physical Metallurgy”,...

    S E T协 议 形 式 化 模 型 的 建 立 和 安 全 性 分 析

    SET协议包含两个主要阶段:注册阶段和购买阶段。注册阶段的目的是让交易参与者获得权威机构颁发的数字证书,以便在后续的购买阶段交易过程中证明自己的身份。购买阶段则是实际的电子商务交易过程,涉及持卡人、商家...

    ECShop——会员退出不清空购物车

    为了实现这一功能,我们需要对以下两个文件进行修改: 1. **\includes\cls_session.php**:此文件负责处理与用户会话相关的操作。 2. **\includes\lib_main.php**:该文件包含了一系列用于用户信息更新的功能。 ##...

    lammps实例2.pdf

    在本实例中,我们将关注如何使用LAMMPS来计算金属中的点缺陷,特别是空位和间隙原子的形成能。 首先,我们来理解什么是空位。在晶体结构中,当一个原子从其正常的位置移除后,形成的空位会导致周围原子的重新排列以...

    Intel Software Developer's Manual Volume 2B Instruction Set Reference, N-Z( September 2008).pdf

    英特尔的指令集架构(IA-32)和Intel 64架构是个人电脑和服务器市场中广泛采用的两种架构。这些架构支持多种操作模式,包括实模式、保护模式、长模式等,适用于不同的应用场景和需求。长模式特别用于支持64位的Intel...

    java_泛型类相关介绍.docjava_泛型类相关介绍.doc

    通过对比两个示例可以看出,使用泛型可以显著减少类型转换的代码量,同时还能在编译期检测类型错误,提高代码的安全性和可读性。学习和掌握泛型不仅可以提高编程效率,还能编写出更加健壮和灵活的程序。

    测试培训教材

    切换到“执行流”界面,添加“Sign-On Password”和“Sign-On User Name”两个测试用例: 右键选择“Sign-On User Name”,选择“测试运行计划” 新建执行条件: 设置“Sign-On User Name”的时间...

    ES6新特性二:Iterator(遍历器)和for-of循环详解

    ES6中引入了Iterator(遍历器)和for-of循环这两个新特性,极大地简化了遍历操作的实现方式。在本文中,我们将详细介绍Iterator(遍历器)和for-of循环的实现原理、使用方式和注意事项。 一、Iterator(遍历器) ...

    6西格玛基础知识ppt72.pptx

    正常分布中,一个标准差(1σ)包含68.27%的数据,两个标准差(2σ)包含95.45%,三个标准差(3σ)则涵盖了99.73%的数据。六西格玛意味着六个标准差之外的缺陷率极低,即每一百万机会中只有3.4个缺陷,也就是百万分...

    LotusNotes访问关系数据库的方法

    但它有一个缺陷:只能按列存取信息,而不能按记录存取信息。 2. 利用 LotusScript 数据对象 LSX 兼容模块 使用 LotusScript 语言来编写存取外部数据的函数,Notes 的 ODBCConnection、ODBCQuery 及 ODBCResultSet ...

    西格玛管理(1).pptx

    两个标准差内(即±2σ)包含95.45%的数据;而三个标准差内(即±3σ)则涵盖了99.73%的数据。因此,六西格玛意味着每一百万个机会中只有3.4个缺陷,这是一个非常低的缺陷率,相当于1.96ppb(十亿分之1.96)。 六...

Global site tag (gtag.js) - Google Analytics