How can I make a given difference insensitive to a case?

I have a class in which data is stored as set , and I want to be able to compare objects of this class, such that the case of element letters does not matter. For example, if the collection contains elements that are strings, there should be no difference between "a" and "a" .

To do this, I tried to define an eql? method eql? member elements for case insensitivity, but this does not affect the method - (alias difference ) in the set. So, how should I make - case insensitive?

The following code illustrates the problem:

 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? 
0
source share
2 answers

Ok, firstly, you just save the lines from SomeSet#add , you need to save an Element instance, for example:

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

And you need to implement the hash method in your Element class.

You can convert Element#@element to lowercase and pass its hash.

 def hash element.downcase.hash end 

Full code and demo: http://codepad.org/PffThml2

Edit: for my input comment O (n) above:

The inserts are O (1). From what i see, eql? used only with hash of 2 elements. Since we execute hash in a smaller version of the element, it will be pretty well distributed, but eql? should not be called much (if it is called at all).

+2
source

From the docs:

The equality of each pair of elements is determined in accordance with Object # eql? and the hash of the # object, since Set uses the Hash as storage.

You may also need to implement the hash of the # object.

 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? 
+1
source

All Articles