How do I create a hash in Ruby that compares strings, ignoring case?
To prevent this change from completely breaking independent parts of your program (such as other ruby gems you are using), make a separate class for your insensitive hash.
class HashClod < Hash
def [](key)
super _insensitive(key)
end
def []=(key, value)
super _insensitive(key), value
end
# Keeping it DRY.
protected
def _insensitive(key)
key.respond_to?(:upcase) ? key.upcase : key
end
end
you_insensitive = HashClod.new
you_insensitive['clod'] = 1
puts you_insensitive['cLoD'] # => 1
you_insensitive['CLod'] = 5
puts you_insensitive['clod'] # => 5
After overriding the assignment and retrieval functions, it's pretty much cake. Creating a full replacement for Hash would require being more meticulous about handling the aliases and other functions (for example, #has_key? and #store) needed for a complete implementation. The pattern above can easily be extended to all these related methods.
Compare two hashes no matter symbols or strings, rails
How about this?
require 'set'
def sorta_equal?(sym_hash, str_hash)
return false unless sym_hash.size == str_hash.size
sym_hash.to_a.to_set == str_hash.map { |pair|
pair.map { |o| o.is_a?(String) ? o.to_sym : o } }.to_set
end
sym_hash= {:id=>58, :locale=>:"en-US"}
sorta_equal?(sym_hash, {"id"=>58, "locale"=>"en-US"}) #=> true
sorta_equal?(sym_hash, {"locale"=>"en-US", "id"=>58 }) #=> true
sorta_equal?(sym_hash, {"id"=>58, "local"=>"en-US", "a"=>"b" }) #=> false
sorta_equal?(sym_hash, {"id"=>58, "lacole"=>"en-US"}) #=> false
sorta_equal?(sym_hash, {"id"=>58, [1,2,3]=>"en-US"}) #=> false
sorta_equal?({}, {}) #=> true
class A; end
a = A.new
sorta_equal?({:id=>a, :local=>:b}, {"id"=>a, "local"=>"b"}) #=> true
Convert hash keys to lowercase -- Ruby Beginner
You can use something like this:
CSV.foreach(file, :headers => true) do |row|
new_hash = {}
row.to_hash.each_pair do |k,v|
new_hash.merge!({k.downcase => v})
end
Users.create!(new_hash)
end
I had no time to test it but, you can take idea of it.
Hope it will help
String values as hash keys, copy created
From Hash.[]=
documentation:
key should not have its value changed while it is in use as a key (an
unfrozen String passed as a key will be duplicated and frozen).
Since by default, strings are not immutable in ruby, theoretically you can change them after you set them as keys in your hash. If you do that - your hash will become invalid, as it will not be able to find those keys properly.
Since string are ubiquitous and are often used by reference, this way Ruby protects its hashes from unexpected bugs, which are very hard to detect.
Strings that compare equal don't find same objects in Hash
This was a bug in ruby < 2.1.3
$ rvm use 2.1.2
Using /Users/richniles/.rvm/gems/ruby-2.1.2
$ irb
2.1.2 :001 > context = "Marriott International World’s Most ADMIRED Lodging Company by FORTUNE for 14th yr. via @FortuneMagazine http://cnnmon.ie/1kcFZSQ"
=> "Marriott International World’s Most ADMIRED Lodging Company by FORTUNE for 14th yr. via @FortuneMagazine http://cnnmon.ie/1kcFZSQ"
2.1.2 :002 > slice_str = context.slice(105,24) # => "http://cnnmon.ie/1kcFZSQ"
=> "http://cnnmon.ie/1kcFZSQ"
2.1.2 :003 > str = "http://cnnmon.ie/1kcFZSQ"
=> "http://cnnmon.ie/1kcFZSQ"
2.1.2 :004 > redirects = {"http://cnnmon.ie/1kcFZSQ"=>""}
=> {"http://cnnmon.ie/1kcFZSQ"=>""}
2.1.2 :005 > redirects.key?(slice_str)
=> false
2.1.2 :006 > redirects.key?(str)
=> true
but do the same in ruby 2.1.3:
$ rvm use 2.1.3
Using /Users/richniles/.rvm/gems/ruby-2.1.3
$ irb
2.1.3 :001 > context = "Marriott International World’s Most ADMIRED Lodging Company by FORTUNE for 14th yr. via @FortuneMagazine http://cnnmon.ie/1kcFZSQ"
=> "Marriott International World’s Most ADMIRED Lodging Company by FORTUNE for 14th yr. via @FortuneMagazine http://cnnmon.ie/1kcFZSQ"
2.1.3 :002 > slice_str = context.slice(105,24) # => "http://cnnmon.ie/1kcFZSQ"
=> "http://cnnmon.ie/1kcFZSQ"
2.1.3 :003 > str = "http://cnnmon.ie/1kcFZSQ"
=> "http://cnnmon.ie/1kcFZSQ"
2.1.3 :004 > redirects = {"http://cnnmon.ie/1kcFZSQ"=>""}
=> {"http://cnnmon.ie/1kcFZSQ"=>""}
2.1.3 :005 > redirects.key?(slice_str)
=> true
2.1.3 :006 > redirects.key?(str)
=> true
How do I compare two hashes?
You can compare hashes directly for equality:
hash1 = {'a' => 1, 'b' => 2}
hash2 = {'a' => 1, 'b' => 2}
hash3 = {'a' => 1, 'b' => 2, 'c' => 3}
hash1 == hash2 # => true
hash1 == hash3 # => false
hash1.to_a == hash2.to_a # => true
hash1.to_a == hash3.to_a # => false
You can convert the hashes to arrays, then get their difference:
hash3.to_a - hash1.to_a # => [["c", 3]]
if (hash3.size > hash1.size)
difference = hash3.to_a - hash1.to_a
else
difference = hash1.to_a - hash3.to_a
end
Hash[*difference.flatten] # => {"c"=>3}
Simplifying further:
Assigning difference via a ternary structure:
difference = (hash3.size > hash1.size) \
? hash3.to_a - hash1.to_a \
: hash1.to_a - hash3.to_a
=> [["c", 3]]
Hash[*difference.flatten]
=> {"c"=>3}
Doing it all in one operation and getting rid of the difference
variable:
Hash[*(
(hash3.size > hash1.size) \
? hash3.to_a - hash1.to_a \
: hash1.to_a - hash3.to_a
).flatten]
=> {"c"=>3}
How can I make hash key lookup case-insensitive?
You will have to use a tied hash. For example Hash::Case::Preserve.
How do I alphabetize an array ignoring case?
How about:
wordlist.sort_by { |word| word.downcase }
Or even shorter:
wordlist.sort_by(&:downcase)
Related Topics
Get Sidekiq to Execute a Job Immediately
Difference Between Integer(Value) and Value.To_I
Ruby Timeouts and System Commands
In Ruby Why Does Nil.Id Return 4
Getting Openssl::X509::Certificateerror Nested Asn1 Error on Ruby
Rails 3.2 'Link_To' (In Email) with 'Method: :Put' Still Producing Get Request
Why Is Rails Outputting My Array
When to Use Nested Classes and Classes Nested in Modules
Error: Error Installing Capybara-Webkit:
Rails Unable to Convert Unpermitted Parameters to Hash
Ruby: Creating a Sandboxed Eval
What Is '-Mix' in a Ruby Regular Expression
What Does "<Top (Required)>" Mean in a Ruby Stack Trace