从一个哈希表中生成多个子哈希表

6

我有一个哈希表:

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多个键/值对,因此如果有任何建议,最好使用动态方法。


3
选择第一个回答可能会让其他人灰心丧气,同时打断仍在考虑回答的人。没有必要着急,很多人会等待至少几个小时才选择回答,有些人甚至等更久。 - Cary Swoveland
1
好的,谢谢你的建议,我是新来的 :) - P.F.
事实上,有些人等了数月之久!而其他人则从未这样做过!LOL - Ed de Almeida
@A.D. 这个问题被标记为过于宽泛:目前而言,这个问题确实太宽泛了:“最佳方式”可以指“最小的代码”,“最快的代码”,“最易读的代码”等等。请在你的问题中更加具体明确。 - Jorge Leitao
2个回答

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
这看起来就像 OP 所寻找的。如果 OP 对这种类型的东西感兴趣,也可以让它更加简洁。hash.group_by { |k, _| k.split('_')[1] }.values.map(&:to_h) - Damon

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"}}

下一个枚举值已生成并传递给块,接下来进行以下计算。
(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"}]

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