Как я создаю хеш в Ruby, который сравнивает строки, игнорируя регистр?

В Ruby я хочу сохранить некоторый материал в Хеше, но я не хочу, чтобы он был чувствителен к регистру. Так, например:

h = Hash.new
h["HELLO"] = 7
puts h["hello"]

Это должно произвести 7, даже при том, что случай отличается. Я могу просто переопределить метод равенства хеша или чего-то подобного?

Спасибо.

17
задан Colen 8 January 2010 в 19:59
поделиться

5 ответов

[

] Чтобы это изменение не нарушало полностью независимые части вашей программы (такие как другие рубиновые драгоценные камни, которые вы используете), сделайте отдельный класс для вашего нечувствительного хэша.[

] [
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
] [

]После переопределения функций присваивания и извлечения, это практически пирог. Создание полной замены Hash потребует более тщательной работы с псевдонимами и другими функциями (например, #has_key? и #store), необходимыми для полной реализации. Вышеприведенный паттерн можно легко распространить на все эти связанные методы.[

].
16
ответ дан 30 November 2019 в 11:52
поделиться
[

]По какой причине вы не просто используете string#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
] [

]Я также рекомендую сделать это, используя модуль_eval.[

]
2
ответ дан 30 November 2019 в 11:52
поделиться
[
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
ответ дан 30 November 2019 в 11:52
поделиться
[

] Если вы действительно хотите игнорировать регистр в обоих направлениях и обрабатывать все методы Хэша, такие как [] #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
]
16
ответ дан 30 November 2019 в 11:52
поделиться
[

] В общем, я бы сказал, что это плохой план, но на вашем месте я бы создал подкласс гашиша, который перекрывает [][][] метод:[

] [
class SpecialHash < Hash
  def [](search)
    # Do special code here
  end
end
]
1
ответ дан 30 November 2019 в 11:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: