论坛首页 编程语言技术论坛

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

浏览 8961 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-08-06   最后修改:2009-09-16
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)。
   发表时间:2009-08-07  
1) Set 的 map!() 方法是collect!()的别名,map() 方法是来自于Enumerable的,所以语义不同。

2) 在你的代码中,s1和s2是不同第两个对象,你可以输出它们的对象id(object_id)看看。如果你对此不满意可以重写Set的<<方法。
0 请登录后投票
   发表时间: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?的区别。

0 请登录后投票
   发表时间: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]}>



0 请登录后投票
   发表时间:2009-08-07  
Hooopo 写道


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

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



我只是不明白两个元素相同的Set为什么不eql? 有什么更深的含义吗?
0 请登录后投票
   发表时间:2009-08-07   最后修改: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]
0 请登录后投票
   发表时间:2009-08-07   最后修改: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



0 请登录后投票
   发表时间: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


0 请登录后投票
   发表时间:2009-08-07  
---看错的分割线---
发现add是<<别名

在我机器上测试 << 是正常的:
ruby -v
ruby 1.8.7 (2009-04-08 patchlevel 160) [i686-linux]
0 请登录后投票
   发表时间: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.....
0 请登录后投票
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics