执行分组并创建具有聚合值的哈希

时间:2014-07-29 12:21:51

标签: ruby

我有一个SQL查询的数组:

Array = [
        ["a","ab",1,548], ["a","ab",2,215],
        ["b","ba",1,999], ["c","ca",1,784]
        ]

不可能在子阵列 的“第三行”中使用两个相同的值,其中2个第一个相同的值/阅读帖子的每一行

["a","ab",**1**,548], ["a","ab",**2**,215]可能,但

["a","ab",**1**,548], ["a","ab",**1**,895]不可能

它来自SQL“group by”查询3个第一个值。

预期结果:

Array = [ ["a","ab", {1=>548, 2=>215} ], 
["b","ba", {1=>999} ], ["c","ca", {1=>784}] ]

我尝试了group_by map的某些组合,但我没有成功。

Array.rows.group_by{|v| v}.map do |k|
  k[0] << {k[0][2]=>k[0][3]}
end

我明白了:

Array = [ ["a","ab", {1=>548} ], ["a","ab", {2=>215} ],
["b","ba", {1=>999} ], ["c","ca", {1=>784}] ]

"a","ab"未合并。

编辑:我忘了,2个第一个值可以是零。 [nil,nil,1,875]

2 个答案:

答案 0 :(得分:4)

a = [["a","ab",1,548], ["a","ab",2,215],["b","ba",1,999], ["c","ca",1,784]]

a.group_by { |e| e.shift(2) }.map { |k, v| k << Hash[v] }
# => [["a", "ab", {1=>548, 2=>215}], ["b", "ba", {1=>999}], ["c", "ca", {1=>784}]] 

group_by按前两个键创建组,将最后两个键保留为值:

# => {["a", "ab"]=>[[1, 548], [2, 215]], ["b", "ba"]=>[[1, 999]], ["c", "ca"]=>[[1, 784]]} 

这已经非常类似于您的需求,您只需要将Hash切换为Array,将Array切换为Hash - 这就是{ {1}}确实。

重要说明:此解决方案 destructive ,这意味着在运行此代码时map本身会发生更改(a更改实际数组数组。)

答案 1 :(得分:1)

您可以使用以下方法,将值“键”(即第一个和第二个元素)分组,并另外创建第3个元素到第4个元素的哈希值。这似乎就是你想要的。

array = [
  ["a","ab",1,548], ["a","ab",2,215],
  ["b","ba",1,999], ["c","ca",1,784]
]

result = array.inject({}) { |h, sub|
  key, idx, val = sub[0..1], sub[2], sub[3]
  h.tap { (h[key] ||= {})[idx] = val }
}.map { |k,v| k << v }

# => [["a", "ab", {1=>548, 2=>215}], ["b", "ba", {1=>999}], ["c", "ca", {1=>784}]]