【问题标题】:Multiple sub-hashes out of one hash一个哈希中的多个子哈希
【发布时间】:2017-04-24 05:36:42
【问题描述】:

我有一个哈希:

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

【问题讨论】:

  • 如此快速地选择提供的第一个答案可能会阻止其他答案,并使仍在研究答案的人短路。不用着急。这里的许多人至少要等几个小时才能选择答案,有些人等待的时间要长得多。
  • 好的,谢谢你的建议,我是新来的:)
  • 其实有的要等几个月!别人从来没有!哈哈
  • @A.D.这个问题被标记为太宽泛:就目前而言,这个问题确实太宽泛了:“最好的方法”可能意味着“最小的代码”、“最快的代码”、“最易读的代码”等。请在什么中更具体说明你的问题是。

标签: ruby regex hash


【解决方案1】:

代码

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 的其余四个元素被传递到块后,返回下面的has。

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

【讨论】:

    【解决方案2】:

    如果您只关心中间组件,您可以使用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"}]
    

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

    【讨论】:

    • 这看起来像 OP 正在寻找的东西。如果 OP 对那种东西感兴趣,也可以让它更简洁hash.group_by { |k, _| k.split('_')[1] }.values.map(&amp;:to_h)
    猜你喜欢
    • 2015-02-08
    • 2014-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-20
    • 2020-02-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多