简体   繁体   English

Ruby group_by具有不同键的哈希数组(键不固定)

[英]Ruby group_by an array of hashes with different keys(keys are not fixed)

I want to group array of hashes present as: 我想将散列数组分组为:

array = [{"value"=>[{"a"=>1},{"b"=>4}]},{"value"=>[{"c"=>4},{"d"=>3},{"a"=>3},{"b"=>54}]}]

to: 至:

grouped_data = {"a"=>[1,3],"b"=>[4,54],"c"=>[4],"d"=>[3]}

I can convert array to array#1 = [{"a"=>1}, {"b"=>4}, {"c"=>4}, {"d"=>3}, {"a"=>3}, {"b"=>54}] using array.map(&:values).flatten . 我可以将数组转换为array#1 = [{"a"=>1}, {"b"=>4}, {"c"=>4}, {"d"=>3}, {"a"=>3}, {"b"=>54}]使用array.map(&:values).flatten I can convert array#1 to how it was with the hash grouped_data using looping over all the data. 通过遍历所有数据,我可以将array#1转换为散列grouped_data的状态。 but i need a more efficient way like using group_by over dynamic keys(keys are not fixed.) 但我需要一种更有效的方式,例如通过动态键使用group_by(键不固定。)

I know how to group if key is fixed. 我知道如果密钥是固定的,如何分组。 i need to group_by on dynamically changing keys. 我需要group_by动态更改密钥。

I don't expect to win any readability awards for this one... 我不希望为此赢得任何可读性奖...

array.map(&:values)
     .flatten
     .group_by { |o| o.keys.first }
     .map { |key, v| [key, v.map(&:values).flatten] }
     .to_h
=> {"a"=>[1, 3], "b"=>[4, 54], "c"=>[4], "d"=>[3]}

I put together some rough benchmarks if anyone was curious: 如果有人好奇,我会汇总一些粗略的基准测试:

require 'benchmark'

n = 10000
letters = ('a'...'z').to_a
numbers = (0...1000).to_a

built_array = []
n.times do |i|
  values = []
  obj_size = (1...letters.size).to_a.sample
  obj_size.times do |j|
    values << {
      "#{letters.sample}" => numbers.sample
    }
  end
  built_array << { "value" => values }
end

Benchmark.bm(15) do |x|
  x.report("anthony") { anthony(built_array) }
  x.report("eric each") { eric_each(built_array) }
  x.report("eric ewo") { eric_each_with_object(built_array) }
  x.report("eric merge") { eric_merge(built_array) }
  x.report("ed inject") { ed_inject(built_array) }
end

                      user     system      total        real
anthony           0.130000   0.010000   0.140000 (  0.146601)
eric each         0.060000   0.000000   0.060000 (  0.067160)
eric ewo          0.070000   0.000000   0.070000 (  0.076125)
eric merge       25.250000   0.880000  26.130000 ( 28.297592)
ed inject         0.080000   0.010000   0.090000 (  0.111045)

Interesting data structure you have here :D 你在这里有趣的数据结构:D

with each 与每个

array = [{ 'value' => [{ 'a' => 1 }, { 'b' => 4 }] }, { 'value' => [{ 'c' => 4 }, { 'd' => 3 }, { 'a' => 3 }, { 'b' => 54 }] }]

grouped_data = Hash.new { |h, k| h[k] = [] }

array.each do |subhash|
  subhash['value'].each do |subsubhash|
    subsubhash.each do |key, value|
      grouped_data[key] << value
    end
  end
end

p grouped_data
#=> {"a"=>[1, 3], "b"=>[4, 54], "c"=>[4], "d"=>[3]}

each_with_object each_with_object

With your proposed code, you could also write : 使用建议的代码,您还可以编写:

grouped_data = Hash.new { |h, k| h[k] = [] }

p array.map(&:values).flatten.each_with_object(grouped_data){|subhash,data| 
  subhash.each do |k,v|
    data[k] << v
  end
}
#=> {"a"=>[1, 3], "b"=>[4, 54], "c"=>[4], "d"=>[3]}

merge 合并

Another option would be with merge : 另一个选择是合并:

p array.map(&:values).flatten.inject{|mem,hash| mem.merge(hash){|k,o,n| [o,n].flatten}}
#=> {"a"=>[1, 3], "b"=>[4, 54], "c"=>4, "d"=>3}

Note that the output is different though. 注意,输出是不同的。 If there's only one value for a letter, it's returned as an integer, not as a 1-element array. 如果一个字母只有一个值,则以整数形式返回,而不是以1元素数组形式返回。

I agree with Eric Duminil. 我同意埃里克·杜米尼尔(Eric Duminil)的观点。 Interesting data structure. 有趣的数据结构。

With #inject 使用#inject

array = [{"value"=>[{"a"=>1},{"b"=>4}]},{"value"=>[{"c"=>4},{"d"=>3},{"a"=>3},{"b"=>54}]}]

new_hash = array.inject(Hash.new) do |h,o|
  o['value'].each do |sh|
    h[sh.keys[0]] = [] if h[sh.keys[0]].nil?
    h[sh.keys[0]] << sh.values[0] 
  end
  h
end

puts new_hash

This won't beat Eric's answer using #merge in shortness, but will do the thing: 简而言之 ,这不会用#merge击败Eric的答案,但是会做到这一点:

#=> {"a"=>[1, 3], "b"=>[4, 54], "c"=>4, "d"=>3}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM