如何使设置差异对案例不敏感?

时间:2012-12-21 17:05:22

标签: ruby

我有一个类,其中数据存储为set,我希望能够比较该类的对象,使得元素的字母大小写无关紧要。例如,如果集合包含字符串元素,那么"a""A"之间应该没有区别。

为此,我尝试将set成员的eql?方法定义为对case不敏感,但这对Set中的方法-(别名difference)没有影响。那么,我应该如何使-对案件不敏感?

以下代码说明了问题:

require 'set'

class SomeSet
  include Enumerable

  def initialize; @elements = Set.new; end

  def add(o)
    @elements.add(o)
    self
  end

  def each(&block)              # To enable +Enumerable+
    @elements.each(&block)
  end

  def difference(compared_list)
    @elements - compared_list
  end
end

class Element
  attr_reader :element

  def initialize(element); @element = element; end

  # This seems to have no effect on +difference+
  def eql?(other_element)
    element.casecmp(other_element.element) == 0
  end
end

set1 = SomeSet.new
set2 = SomeSet.new
set1.add("a")
set2.add("A")

# The following turns out false but I want it to turn out true as case
# should not matter.
puts set1.difference(set2).empty?

2 个答案:

答案 0 :(得分:2)

好的,首先,您只是存储来自SomeSet#add的字符串,您需要存储Element的实例,如下所示:

def add(o)
  @elements.add(Element.new(o))
  self
end

您需要在hash课程中实施Element方法。

您可以将Element#@element转换为小写,然后传递其哈希值。

def hash
  element.downcase.hash
end

完整代码和演示:http://codepad.org/PffThml2

编辑:对于我的O(n)插入评论,上面是:

插入是O(1)。从我所看到的情况来看,eql?仅用于hash的2个元素是相同的。当我们对元素的下层版本进行hash时,它将分布得相当好,并且eql?不应被调用太多(如果它被调用的话)。

答案 1 :(得分:1)

来自文档:

  

每个元素的相等性是根据Object#eql确定的?和Object#hash,因为Set使用Hash作为存储。

也许您还需要实现Object#hash。

require 'set'

class String2
  attr_reader :value

  def initialize v
    @value = v
  end

  def eql? v
    value.casecmp(v.value) == 0
  end

  def hash
    value.downcase.hash
  end
end

set1 = Set.new
set2 = Set.new
set1.add(String2.new "a")
set2.add(String2.new "A")

puts set1.difference(set2).empty?