一个哈希中的多个子哈希

时间:2016-12-08 20:51:18

标签: ruby regex hash

我有一个哈希:

hash = {"a_1_a" => "1", "a_1_b" => "2", "a_1_c" => "3", "a_2_a" => "3",
        "a_2_b" => "4", "a_2_c" => "4"}

获得以下子哈希的最佳方法是什么:

[{"a_1_a" => "1", "a_1_b" => "2", "a_1_c" => "3"},
 {"a_2_a" => "3", "a_2_b" => "4", "a_2_c" => "4"}]

我希望它们根据正则表达式/^a_(\d+)/按键分组。我在原始哈希中有50多个键/值对,因此如果有人有任何建议,那么动态的东西最有效。

2 个答案:

答案 0 :(得分:7)

如果你只关心中间组件,你可以使用group_by来帮助你完成大部分工作:

hash.group_by do |k,v|
  k.split('_')[1]
end.values.map do |list|
  Hash[list]
end

# => [{"a_1_a"=>"1", "a_1_b"=>"2", "a_1_c"=>"3"}, {"a_2_a"=>"3", "a_2_b"=>"4", "a_2_c"=>"4"}]

最后一步是提取分组列表并将它们组合回所需的哈希值。

答案 1 :(得分:4)

<强>代码

def partition_hash(hash)
  hash.each_with_object({}) do |(k,v), h|
    key = k[/(?<=_).+(?=_)/]
    h[key] = (h[key] || {}).merge(k=>v)
  end.values
end

示例

hash = {"a_1_a"=>"1", "a_1_b"=>"2", "a_1_c"=>"3", "a_2_a"=>"3", "a_2_b"=>"4", "a_2_c"=>"4"}
partition_hash(hash)
  #=> [{"a_1_a"=>"1", "a_1_b"=>"2", "a_1_c"=>"3"},
  #    {"a_2_a"=>"3", "a_2_b"=>"4", "a_2_c"=>"4"}] 

<强>解释

步骤如下。

enum = hash.each_with_object({})
  #=> #<Enumerator: {"a_1_a"=>"1", "a_1_b"=>"2", "a_1_c"=>"3", "a_2_a"=>"3",
  #                  "a_2_b"=>"4", "a_2_c"=>"4"}:each_with_object({})> 

生成此枚举数的第一个元素并将其传递给块,并使用并行赋值计算块变量。

(k,v), h = enum.next
  #=> [["a_1_a", "1"], {}] 
k #=> "a_1_a" 
v #=> "1" 
h #=> {} 

并执行块计算。

key = k[/(?<=_).+(?=_)/]
  #=> "1" 
h[key] = (h[key] || {}).merge(k=>v)
  #=> h["1"] = (h["1"] || {}).merge("a_1_a"=>"1")
  #=> h["1"] = (nil || {}).merge("a_1_a"=>"1")
  #=> h["1"] = {}.merge("a_1_a"=>"1")
  #=> h["1"] = {"a_1_a"=>"1"} 

所以现在

h #=> {"1"=>{"a_1_a"=>"1"}}

现在生成enum的下一个值并将其传递给块,并执行以下计算。

(k,v), h = enum.next
  #=> [["a_1_b", "2"], {"1"=>{"a_1_a"=>"1"}}] 
k #=> "a_1_b" 
v #=> "2" 
h #=> {"1"=>{"a_1_a"=>"1"}} 

key = k[/(?<=_).+(?=_)/]
  #=> "1" 
h[key] = (h[key] || {}).merge(k=>v)
  #=> h["1"] = (h["1"] || {}).merge("a_1_b"=>"2")
  #=> h["1"] = ({"a_1_a"=>"1"}} || {}).merge("a_1_b"=>"2")
  #=> h["1"] = {"a_1_a"=>"1"}}.merge("a_1_b"=>"2")
  #=> h["1"] = {"a_1_a"=>"1", "a_1_b"=>"2"}

在将enum的其余四个元素传递给块后,将返回以下内容。

h #=> {"1"=>{"a_1_a"=>"1", "a_1_b"=>"2", "a_1_c"=>"3"},
  #    "2"=>{"a_2_a"=>"3", "a_2_b"=>"4", "a_2_c"=>"4"}}

最后一步只是提取值。

h.values
  #=> [{"a_1_a"=>"1", "a_1_b"=>"2", "a_1_c"=>"3"},
  #    {"a_2_a"=>"3", "a_2_b"=>"4", "a_2_c"=>"4"}]