2010-01-08 64 views

回答

11

为了防止你的程序完全打破独立的部分(如其他红宝石宝石你正在使用)这一变化,让一个单独的类为您的敏感哈希值。

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)。上面的模式可以很容易地扩展到所有这些相关的方法。

+3

我意识到这是近五年前,但'你不敏感的土块'让我大声笑出来。布拉沃。 – 2014-12-22 22:06:28

+0

警告:这不适用于嵌套散列。 – jrg 2016-01-18 21:57:32

+0

@James据我所知,它确实如果你创建每个嵌套级别作为一个HashClod。如果你创建默认哈希当然会失败。 – 2016-01-21 00:37:05

1

任何不只是使用字符串#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来做这件事。

+0

H [“HELLO “] = 7? – 2010-01-08 20:59:29

+0

假设设置散列正在全部大写。您可以轻松地将以上内容扩展到[] = – mletterle 2010-01-08 21:09:56

1

一般来说,我会说这是一个糟糕的计划;但是,如果我是你,我想创建哈希的子类,覆盖[]方法:

class SpecialHash < Hash 
    def [](search) 
    # Do special code here 
    end 
end 
+1

只需在该答案中添加更多内容:重写#[] =在您接收的键上调用#downcase,然后在#[]中调用self.get(search。 downcase)。 – 2010-01-08 20:16:28

+0

@Federico Builes - +1 - 感谢额外的位:-) – 2010-01-08 20:40:43

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

当然,如果key没有实现一个名为upcase的方法,这将会炸毁... – mletterle 2010-01-08 20:19:33

14

如果你真的想忽略两个方向的情况下,并处理所有的哈希方法,如#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 
+1

整洁,我不知道! – 2010-01-08 20:52:03

+3

警告,这种方法不适用于嵌套散列,因为你的子类不会被使用 – 2013-04-23 15:34:59

0

尽管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} 
+0

作为一个后续,我真正需要的是一个忽略/保存案例的散列,但是HashWithIndifferentAccess的子类化最终会消除原始键的情况(更不用说上面的[]方法bug了),所以我放弃了monkeypatched fetch_indifferently方法而不是哈希。 – rantler 2012-07-17 23:07:52

相关问题