映射具有相同名称的键

时间:2014-10-01 15:29:59

标签: ruby json map

对我正在使用的API端点的GET返回json,其联系人顺序不一致

{"contacts"=>[
  {"id"=>$UUID_0, "name"=>nil, "email"=>$EMAIL_0, "phone"=>$PHONE_0, "type"=>"foo"},
  {"id"=>$UUID_1, "name"=>nil, "email"=>$EMAIL_1, "phone"=>$PHONE_1, "type"=>"bar"}
]}

{"contacts"=>[
  {"id"=>$UUID_1, "name"=>nil, "email"=>$EMAIL_1, "phone"=>$PHONE_1, "type"=>"bar"},
  {"id"=>$UUID_0, "name"=>nil, "email"=>$EMAIL_0, "phone"=>$PHONE_0, "type"=>"foo"}
]}

"type"值是这些响应中唯一的静态对象,所以我想映射它,以便联系类型是包含其他对的键:

{
  "foo"=>{"id"=>$UUID_0, "name"=>$NAME_0, "email"=>$EMAIL_0, "phone"=>$PHONE_0},
  "bar"=>{"id"=>$UUID_1, "name"=>$NAME_1, "email"=>$EMAIL_1, "phone"=>$PHONE_1}
}

解决方案对我来说并不明显。

3 个答案:

答案 0 :(得分:1)

如果您使用Ruby on Rails或至少使用ActiveSupport,则可以尝试index_by而不是group_by:它不会将值放入数组中。

hash['contacts'].index_by {|r| r['type']}
=>
{
  "bar" => {
    "id"    => "asdf",
    "name"  => nil,
    "email" => "EMAIL_1",
    "phone" => "PHONE_1",
    "type"  => "bar"
  },
  "foo" => {
    "id"    => "asdf",
    "name"  => nil,
    "email" => "EMAIL_0",
    "phone" => "PHONE_0",
    "type"  => "foo"
  }
}

答案 1 :(得分:0)

这可以使用Enumerable#reduce:

来完成
hash['contacts'].reduce({}) {|m,c| m[c['type']] = c;m}

工作原理:

  1. 空哈希是起点。
  2. 为联系人列表中的每个元素调用一次该块。该块接收我们正在构建为m的哈希值和当前联系人c
  3. 在块中,根据c将哈希值分配给type并返回哈希值。
  4. 最终结果是块的最后一个返回值。

答案 2 :(得分:0)

Hash[data['contacts'].map { |c| [c['type'], c] }]