如何连接一个键的不同值

时间:2017-11-26 16:57:24

标签: ruby

我有几天遇到麻烦,我需要帮助来解决它。 我有一个哈希,它具有相同键的多个值:

{"answers":
  [
    {"id":1,"value":true},
    {"id":3,"value":false},
    {"id":2,"value":3},
    {"id":1,"value":false},
    {"id":2,"value":false},
    {"id":2,"value":1}
  ]
} 

我想要一种方法来对一个键的所有值进行分组,例如:

{
  "answers": [
    {
      "id":1, "value": [true, false]    
    },  
    {
      "id":3, "value": [false]
    },
    {
      "id":2, "value":[3, false, 1]
    }
  ]
}

我尝试过使用reduce方法,但是我找不到将值链接到键的方法。 任何人都可以帮助我吗? 谢谢!

2 个答案:

答案 0 :(得分:2)

看起来您希望Enumerable#group_by通过每个哈希中的:id键重新组合哈希数组。

此方法获取answers数组并返回一个新的,已转换的答案数组:

def transform_answers(answers)
  answers
    .group_by { |h| h[:id] }
    .each_value { |a| a.map! { |h| h[:value] } }
    .map { |id, value| { id: id, value: value } }
end

你可以像这样使用它:

hash = {
  answers: [
    { id: 1, value: true },
    { id: 1, value: false },
    { id: 2, value: 3 },
    { id: 2, value: false },
    { id: 2, value: 1 },
    { id: 3, value: false }
  ]
}

transformed_answers = transform_answers(hash[:answers]) # => [{:id=>1, :value=>[true, false]}, {:id=>2, :value=>[3, false, 1]}, {:id=>3, :value=>[false]}]

您可以轻松获取已转换的答案并将其放回类似于原始输入的哈希值:

transformed_hash = { answers: transformed_answers }

答案 1 :(得分:1)

hash = {
  answers: [
    { id: 1, value: true },
    { id: 1, value: false },
    { id: 2, value: 3 },
    { id: 2, value: false },
    { id: 2, value: 1 },
    { id: 3, value: false }
  ]
}

def doit(answers)
  answers.each_with_object({}) do |g,h|
    h.update(g[:id]=>{ id: g[:id], value: [g[:value]] }) do |_,o,n|
      { id: o[:id], value: o[:value]+n[:value] }
    end
  end.values
end

{ answers: doit(hash[:answers]) }
    #=> {:answers=>[
    #      {:id=>1, :value=>[true, false]},
    #      {:id=>2, :value=>[3, false, 1]},
    #      {:id=>3, :value=>[false]}
    #    ]
    #   }

这使用Hash#update(aka merge!)的形式,它使用一个块来确定合并的两个哈希中存在的键的值。该块是

do |_k,o,n|
  { id: o[:id], value: o[:value]+n[:value] }
end

有关三个块变量的定义,请参阅update的文档,_kon。我编写了第一个块变量(公共密钥)_k,而不是k,以表示它未在块计算中使用。

请注意,在values中执行doit之前,该方法构造了以下哈希值。

{1=>{:id=>1, :value=>[true, false]},
 2=>{:id=>2, :value=>[3, false, 1]},
 3=>{:id=>3, :value=>[false]}}