我尝试学习地图和group_by,但这很难......
我的数组数组:
a = [ [1, 0, "a", "b"], [1, 1, "c", "d"], [2, 0, "e", "f"], [3, 1, "g", "h"] ]
预期结果:
b= {
1=> {0=>["a", "b"], 1=>["c", "d"]} ,
2=> {0=>["e", "f"]} ,
3=> {1=>["g", "h"]}
}
按first value
分组,第二个值可以是0
或1
。
一个开始:
a.group_by{ |e| e.shift}.map { |k, v| {k=>v.group_by{ |e| e.shift}} }
=> [{1=>{0=>[["a", "b"]], 1=>[["c", "d"]]}},
{2=>{0=>[["e", "f"]]}}, {3=>{1=>[["g", "h"]]}}]
我希望得到带有2个第一个值的“a”和“b”,这是我找到的唯一解决方案......(使用散列哈希)
答案 0 :(得分:4)
不确定group_by
是否是最简单的解决方案:
a = [ [1, 0, "a", "b"], [1, 1, "c", "d"], [2, 0, "e", "f"], [3, 1, "g", "h"] ]
result = a.inject({}) do |acc,(a,b,c,d)|
acc[a] ||= {}
acc[a][b] = [c,d]
acc
end
puts result.inspect
将打印:
{1=>{0=>["a", "b"], 1=>["c", "d"]}, 2=>{0=>["e", "f"]}, 3=>{1=>["g", "h"]}}
另外,请避免直接更改您正在操作的项目(shift
来电),您在代码中可能收到的馆藏可能不属于您的更改。
答案 1 :(得分:1)
如果你想要一个有点自定义的group_by
我倾向于手动做。 group_by
创建一个分组值数组,因此它会创建[["a", "b"]]
而不是["a", "b"]
。此外,您的代码具有破坏性,即它操纵a
的值。如果您计划稍后以原始形式重新使用a
,这只是一件坏事,但重要的是要注意。
正如我所提到的那样,您也可以只遍历a
一次并构建所需的结构,而不是执行多个group_by
。
b = {}
a.each do |aa|
(b[aa[0]] ||= {})[aa[1]] = aa[2..3]
end
b # => {1=>{0=>["a", "b"], 1=>["c", "d"]}, 2=>{0=>["e", "f"]}, 3=>{1=>["g", "h"]}}
使用(b[aa[0]] ||= {})
,我们会检查哈希aa[0]
中是否存在密钥b
。如果它不存在,我们为该键分配一个空哈希({}
)。接下来,我们将aa
(= aa[2..3]
)的最后两个元素插入到该哈希中,并将aa[1]
作为键。
请注意,这不会考虑重复的主要/辅助密钥。也就是说,如果您有其他条目[1, 1, "x", "y"]
,它将覆盖 [1, 1, "c", "d"]
条目,因为它们都有密钥1
和1
。你可以通过将值存储在一个数组中来解决这个问题,但是你也可以做一个双group_by
。例如,对a
的破坏性行为,处理“重复”:
# Added [1, 1, "x", "y"], removed some others
a = [ [1, 0, "a", "b"], [1, 1, "c", "d"], [1, 1, "x", "y"] ]
b = Hash[a.group_by(&:shift).map { |k, v| [k, v.group_by(&:shift) ] }]
#=> {1=>{0=>[["a", "b"]], 1=>[["c", "d"], ["x", "y"]]}}
答案 2 :(得分:1)
[[1, 0, "a", "b"], [1, 1, "c", "d"], [2, 0, "e", "f"], [3, 1, "g", "h"]].
group_by{ |e| e.shift }.
map{ |k, v| [k, v.inject({}) { |h, v| h[v.shift] = v; h }] }.
to_h
#=> {1=>{0=>["a", "b"], 1=>["c", "d"]}, 2=>{0=>["e", "f"]}, 3=>{1=>["g", "h"]}}
答案 3 :(得分:1)
以下是如何使用两个Enumerable#group_by和一个Object#tap(非破坏性地)执行此操作的方法。 a
(数组)的元素大小可能不同,每个元素的大小可能是两个或更大。
<强>代码强>
def convert(arr)
h = arr.group_by(&:first)
h.keys.each { |k| h[k] = h[k].group_by { |a| a[1] }
.tap { |g| g.keys.each { |j|
g[j] = g[j].first[2..-1] } } }
h
end
示例强>
a = [ [1, 0, "a", "b"], [1, 1, "c", "d"], [2, 0, "e", "f"], [3, 1, "g", "h"] ]
convert(a)
#=> {1=>{0=>["a", "b"], 1=>["c", "d"]}, 2=>{0=>["e", "f"]}, 3=>{1=>["g", "h"]}}
<强>解释强>
h = a.group_by(&:first)
#=> {1=>[[1, 0, "a", "b"], [1, 1, "c", "d"]],
# 2=>[[2, 0, "e", "f"]],
# 3=>[[3, 1, "g", "h"]]}
keys = h.keys
#=> [1, 2, 3]
传递给块的键的第一个值将值1
赋给块变量k
。我们将h[1]
设置为哈希f
,计算如下。
f = h[k].group_by { |a| a[1] }
#=> [[1, 0, "a", "b"], [1, 1, "c", "d"]].group_by { |a| a[1] }
#=> {0=>[[1, 0, "a", "b"]], 1=>[[1, 1, "c", "d"]]}
我们需要对此哈希进行进一步处理,因此我们使用tap
捕获它并将其分配给tap
的块变量g
(即{{1}最初将等于g
以上)。修改后,块将返回f
。
我们有
g
因此g.keys #=> [0, 1]
是传递到0
块的第一个值并分配给块变量each
。然后我们计算:
j
同样,当g[j] = g[j].first[2..-1]
#=> g[0] = [[1, 0, "a", "b"]].first[2..-1]
#=> ["a", "b"]
的第二个密钥(g
)传递到块中时,
1
人体工程学,
g[j] = g[j].first[2..-1]
#=> g[1] = [[1, 1, "c", "d"]].first[2..-1]
#=> ["c", "d"]
h[1] = g
#=> {0=>["a", "b"], 1=>["c", "d"]}
和h[2]
的计算方法类似,为我们提供了理想的结果。