锁定老帖子 主题:个人感觉关于Set类的两个缺陷
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2009-08-06
最后修改:2009-09-16
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)。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2009-08-07
1) Set 的 map!() 方法是collect!()的别名,map() 方法是来自于Enumerable的,所以语义不同。
2) 在你的代码中,s1和s2是不同第两个对象,你可以输出它们的对象id(object_id)看看。如果你对此不满意可以重写Set的<<方法。 |
|
返回顶楼 | |
发表时间: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?的区别。 |
|
返回顶楼 | |
发表时间: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]}> |
|
返回顶楼 | |
发表时间:2009-08-07
Hooopo 写道 这说明set在判断是否相等与是不是同一个对象无关。 而是和对象的hash值有关。其实就是==和eql?的区别。 我只是不明白两个元素相同的Set为什么不eql? 有什么更深的含义吗? |
|
返回顶楼 | |
发表时间: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] |
|
返回顶楼 | |
发表时间: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 |
|
返回顶楼 | |
发表时间: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 |
|
返回顶楼 | |
发表时间:2009-08-07
---看错的分割线---
发现add是<<别名 在我机器上测试 << 是正常的: ruby -v ruby 1.8.7 (2009-04-08 patchlevel 160) [i686-linux] |
|
返回顶楼 | |
发表时间: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..... |
|
返回顶楼 | |