如何使用Ruby将哈希键更改为小写

11

给定具有嵌套文档的哈希:

myHash = {
  "MemberId"=>"ABC0001", 
  "MemberName"=>"Alan", 
  "details"=>[
    {"LineNumber"=>"4.1", "Item"=>"A0001", "Description"=>"Apple"}, 
    {"LineNumber"=>"5.1", "Item"=>"A0002"}, 
    {"LineNumber"=>"6.1", "Item"=>"Orange"}
  ]
}

我希望将其修改为以下样式:

{
  "memberid"=>"ABC0001", 
  "membername"=>"Alan", 
  "details"=>[
    {"linenumber"=>"4.1", "item"=>"A0001", "description"=>"Apple"}, 
    {"linenumber"=>"5.1", "item"=>"A0002"}, 
    {"linenumber"=>"6.1", "item"=>"Orange"}
  ]
}

换句话说,如果哈希键中有任何小写字母,我想将其转换为小写。我知道我需要遍历哈希并使用 downcase 方法。在 Ruby 中是否有更简单的方法?

6个回答

16

2
这是最好的答案。如果您有嵌套哈希,则应使用deep_transform_keys - David Melin

5
class Hash
  def downcase_key
    keys.each do |k|
      store(k.downcase, Array === (v = delete(k)) ? v.map(&:downcase_key) : v)
    end
    self
  end
end

myHash.downcase_key

对于@cdshines而言,当键本身是哈希表时,此代码无法正常工作。 - ZeDalaye

3
def f h
  Hash[h.map{|k,v| v.class == Array ? [k,v.map{|r| f r}.to_a] : [k.downcase,v]}]
end

证明


3

我首先会在Hash上创建一个方法,允许你将键映射到新值:

class Hash
  def map_keys! &blk
    keys.each do |k|
      new_k = blk.call(k)
      self[new_k] = delete(k)
    end
    self
  end

  def map_keys &blk
    dup.map_keys!(&blk)
  end
end

现在您可以使用以下方法将第一级转换为小写:

myHash.map_keys!(&:downcase)

myHash现在包含:

{"details"=>
  [{"LineNumber"=>"4.1", "Item"=>"A0001", "Description"=>"Apple"},
   {"LineNumber"=>"5.1", "Item"=>"A0002"},
   {"LineNumber"=>"6.1", "Item"=>"Orange"}],
 "memberid"=>"ABC0001",
 "membername"=>"Alan"}

嵌套哈希表可以使用以下方式进行转换:
myHash['details'].each{|h| h.map_keys!(&:downcase) }

myHash现在包含:

{"details"=>
  [{"linenumber"=>"4.1", "item"=>"A0001", "description"=>"Apple"},
   {"linenumber"=>"5.1", "item"=>"A0002"},
   {"linenumber"=>"6.1", "item"=>"Orange"}],
 "memberid"=>"ABC0001",
 "membername"=>"Alan"}

现在只需将所有步骤收集到一个方法中,它就会自动完成 ;) - tkroman
1
我认为编写可重用和易读的代码比将所有内容都适合于一行更重要;-) - Patrick Oscity

1
我在今天解决同样的问题时找到了这个解决方案。
def lowercase_keys(h)
  new_h = { }
  h.each_pair do |k, v|
    new_k = deep_lowercase(k, true)
    new_v = deep_lowercase(v, false)
    new_h[new_k] = new_v
  end
  new_h
end

def deep_lowercase(object, with_strings)
  case object
    when String then
      with_strings ? object.downcase : object
    when Hash then
      lowercase_keys(object)
    else
      object.respond_to?(:map) ? object.map { |e| deep_lowercase(e, false) } : object
  end
end

从我的测试结果来看,无论哈希表中的值或键本身还是嵌入在可枚举对象中,它都可以正常工作。

0
这是一个函数,它可以递归地遍历任意嵌套的可枚举对象,并将其找到的哈希键转换为小写:
data = {
  "MemberId"=>"ABC0001", 
  "MemberName"=>"Alan", 
  "details"=>[
    {"LineNumber"=>"4.1", "Item"=>"A0001", "Description"=>"Apple"}, 
    {"LineNumber"=>"5.1", "Item"=>"A0002"}, 
    {"LineNumber"=>"6.1", "Item"=>"Orange"}
  ]
}

def downcase_hash_keys(h)
  if h.is_a?(Hash)
    h.keys.each do |key|
      new_key = key.to_s.downcase
      h[new_key] = h.delete(key)
      downcase_hash_keys(h[new_key])
    end
  elsif h.respond_to?(:each)
    h.each { |e| downcase_hash_keys(e) }
  end
  h
end

downcase_hash_keys(data)
p data


# => {"memberid"=>"ABC0001", "membername"=>"Alan", "details"=>[{"linenumber"=>"4.1", "item"=>"A0001", "description"=>"Apple"}, {"linenumber"=>"5.1", "item"=>"A0002"}, {"linenumber"=>"6.1", "item"=>"Orange"}]}

这个方法有点丑陋,因为它在原数据结构上做了改变;理想情况下,应该创建一个新的哈希表。但是它实现了我们所期望的结果。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接