在Ruby中,我想将一些东西存储在哈希中,但我不希望它是区分大小写的。例如:如何在Ruby中创建比较字符串的哈希,忽略大小写?
h = Hash.new
h["HELLO"] = 7
puts h["hello"]
即使情况不同,也应输出7。我可以重写散列的相等方法或类似的东西吗?
谢谢。
在Ruby中,我想将一些东西存储在哈希中,但我不希望它是区分大小写的。例如:如何在Ruby中创建比较字符串的哈希,忽略大小写?
h = Hash.new
h["HELLO"] = 7
puts h["hello"]
即使情况不同,也应输出7。我可以重写散列的相等方法或类似的东西吗?
谢谢。
为了防止你的程序完全打破独立的部分(如其他红宝石宝石你正在使用)这一变化,让一个单独的类为您的敏感哈希值。
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
覆盖分配和检索功能后,它几乎是蛋糕。创建哈希的完整替换需要更加细致地处理完整实现所需的别名和其他函数(例如#has_key?和#store)。上面的模式可以很容易地扩展到所有这些相关的方法。
任何不只是使用字符串#upcase的原因?
h = Hash.new
h["HELLO"] = 7
puts h["hello".upcase]
如果你坚持要修改散列,你可以这样做以下
class Hash
alias :oldIndexer :[]
def [](val)
if val.respond_to? :upcase then oldIndexer(val.upcase) else oldIndexer(val) end
end
end
因为它长大了,你也可以这样做是为了设置不区分大小写:
class Hash
alias :oldSetter :[]=
def []=(key, value)
if key.respond_to? :upcase then oldSetter(key.upcase, value) else oldSetter(key, value) end
end
end
我也建议使用module_eval来做这件事。
H [“HELLO “] = 7? – 2010-01-08 20:59:29
假设设置散列正在全部大写。您可以轻松地将以上内容扩展到[] = – mletterle 2010-01-08 21:09:56
一般来说,我会说这是一个糟糕的计划;但是,如果我是你,我想创建哈希的子类,覆盖[]
方法:
class SpecialHash < Hash
def [](search)
# Do special code here
end
end
只需在该答案中添加更多内容:重写#[] =在您接收的键上调用#downcase,然后在#[]中调用self.get(search。 downcase)。 – 2010-01-08 20:16:28
@Federico Builes - +1 - 感谢额外的位:-) – 2010-01-08 20:40:43
require 'test/unit'
class TestCaseIndifferentHash < Test::Unit::TestCase
def test_that_the_hash_matches_keys_case_indifferent
def (hsh = {}).[](key) super(key.upcase) end
hsh['HELLO'] = 7
assert_equal 7, hsh['hello']
end
end
当然,如果key没有实现一个名为upcase的方法,这将会炸毁... – mletterle 2010-01-08 20:19:33
如果你真的想忽略两个方向的情况下,并处理所有的哈希方法,如#has_key?
,#fetch
,#values_at
,#delete
等等,如果你想从头开始构建,你需要做一些工作,但是如果你创建了一个新的类,它扩展自类ActiveSupport::HashWithIndifferentAccess,你应该可以很容易地做到这一点:
require "active_support/hash_with_indifferent_access"
class CaseInsensitiveHash < HashWithIndifferentAccess
# This method shouldn't need an override, but my tests say otherwise.
def [](key)
super convert_key(key)
end
protected
def convert_key(key)
key.respond_to?(:downcase) ? key.downcase : key
end
end
下面是一些例子行为:
h = CaseInsensitiveHash.new
h["HELLO"] = 7
h.fetch("HELLO") # => 7
h.fetch("hello") # => 7
h["HELLO"] # => 7
h["hello"] # => 7
h.has_key?("hello") # => true
h.values_at("hello", "HELLO") # => [7, 7]
h.delete("hello") # => 7
h["HELLO"] # => nil
整洁,我不知道! – 2010-01-08 20:52:03
警告,这种方法不适用于嵌套散列,因为你的子类不会被使用 – 2013-04-23 15:34:59
尽管Ryan McGeary的方法非常好,而且几乎可以肯定是正确的方法,但是有一个错误,我无法辨别原因,从而打破了Hash[]
方法。
例如:
r = CaseInsensitiveHash['ASDF', 1, 'QWER', 2]
=> {"ASDF"=>1, "QWER"=>2}
r['ASDF']
=> nil
ap r
{
"ASDF" => nil,
"QWER" => nil
}
=> {"ASDF"=>1, "QWER"=>2}
虽然我已经无法找到或修复错误的根本原因,下面的技巧确实改善的问题:
r = CaseInsensitiveHash.new(Hash['ASDF', 1, 'QWER', 2])
=> {"asdf"=>1, "qwer"=>2}
r['ASDF']
=> 1
ap r
{
"asdf" => 1,
"qwer" => 2
}
=> {"asdf"=>1, "qwer"=>2}
作为一个后续,我真正需要的是一个忽略/保存案例的散列,但是HashWithIndifferentAccess的子类化最终会消除原始键的情况(更不用说上面的[]方法bug了),所以我放弃了monkeypatched fetch_indifferently方法而不是哈希。 – rantler 2012-07-17 23:07:52
我意识到这是近五年前,但'你不敏感的土块'让我大声笑出来。布拉沃。 – 2014-12-22 22:06:28
警告:这不适用于嵌套散列。 – jrg 2016-01-18 21:57:32
@James据我所知,它确实如果你创建每个嵌套级别作为一个HashClod。如果你创建默认哈希当然会失败。 – 2016-01-21 00:37:05