如果该哈希键匹配,我需要将哈希数组简化为单个哈希。
my_array
是一个哈希数组,每个哈希都有两个键:一个是活动记录对象,另一个是不同活动记录对象的数组,类似于:
my_array = [
{
first_hash_key: {id: 1, title: "my title"},
second_hash_key: ["stuff", "more stuff", "more stuff"]
},
{
first_hash_key: {id: 1, title: "my title"},
second_hash_key: ["stuff 3", "uniq stuff 2"]
},
{
first_hash_key: {id: 2, title: "my other title"},
second_hash_key: ["interesting stuff", "uniq stuff"]
}
]
我想通过first_hash_key[:id]
组合哈希,将hash_key_two
中的每个项目添加到数组中,而不是覆盖它们以获得:
my_array = [
{
first_hash_key: {id: 1, title: "my title"},
second_hash_key: [
["stuff", "more stuff", "more stuff"],
["stuff 3", "uniq stuff 2"]
]
},
{
first_hash_key: {id: 2, title: "my other title"},
second_hash_key: ["interesting stuff", "uniq stuff"]
}
]
我可以减少顶级数组和哈希,并使用merge
,但是我丢失了哈希中的单个数组。
我也尝试过按id
中的first_hash_key
进行分组,然后像这样注入:
my_array.group_by{|h| h[:first_hash_key]}.map{|k,v| v.inject(:merge)}
同样,我丢失了second_hash_key
中的数组。我只得到列出的最后一个数组。如果没有map
,我会得到组中每个哈希的数组,但是顶层没有合并。
[
{
:first_hash_key=>{:id=>1, :title=>"my title"},
:second_hash_key=>["stuff 3", "uniq stuff 2"]
},
{
:first_hash_key=>{:id=>2, :title=>"my other title"},
:second_hash_key=>["interesting stuff", "uniq stuff"]
}
]
更新 正如sawa和cary所指出的那样,如果数据是一个数组或多个数组,最好猜测总是有数组数组,那么就没有必要猜测second_hash_key了。所需的输出是:
[{:first_hash_key=>{:id=>1, :title=>"my title"},
:second_hash_key=>[["stuff", "more stuff", "more stuff"],
["stuff 3", "uniq stuff 2"]]
},
{:first_hash_key=>{:id=>2, :title=>"my other title"},
:second_hash_key=>[["interesting stuff", "uniq stuff"]]
}]
答案 0 :(得分:0)
它不是很漂亮,但是你去了:
my_array.
group_by { |elem| elem[:first_hash_key] }.
transform_values { |vals| vals.map { |val| val[:second_hash_key] } }.
reduce([]) do |memo, (key, vals)|
memo + [{first_hash_key: key, second_hash_key: vals}]
end
返回:
[
{
:first_hash_key=>{:id=>1, :title=>"my title"},
:second_hash_key=>[
["stuff", "more stuff", "more stuff"],
["stuff 3", "uniq stuff 2"]
]
}, {
:first_hash_key=>{:id=>2, :title=>"my other title"},
:second_hash_key=>[
["interesting stuff", "uniq stuff"]
]
}
]
如果您不清楚这是如何工作的,则应检查每行的结果,但要进行总结
first_hash_key
分组调用transform_values
以在second_hash_key
处获取与每个first_hash_key
值相对应的值
这时,您将哈希映射first_hash_key
值映射到second_hash_key
的所有对应值。现在只需reduce
即可获得最终的数据结构。
这种group_by => transform_values => reduce的模式是我一直使用的东西,非常有用。我相信transform_values和ruby 2.5都可以在rails中使用。
答案 1 :(得分:0)
my_array.each_with_object({}) do |g,h|
h.update(g[:first_hash_key][:id]=>g) { |_,o,n|
o.merge(second_hash_key: [[*o[:second_hash_key]], n[:second_hash_key]]) }
end.values
#=> [{:first_hash_key=>{:id=>1, :title=>"my title"},
# :second_hash_key=>[["stuff", "more stuff", "more stuff"],
# ["stuff 3", "uniq stuff 2"]]},
# {:first_hash_key=>{:id=>2, :title=>"my other title"},
# :second_hash_key=>["interesting stuff", "uniq stuff"]}]
Hash#values的接收者是哈希:
{1=>{:first_hash_key=>{:id=>1, :title=>"my title"},
:second_hash_key=>[["stuff", "more stuff", "more stuff"],
["stuff 3", "uniq stuff 2"]]},
2=>{:first_hash_key=>{:id=>2, :title=>"my other title"},
:second_hash_key=>["interesting stuff", "uniq stuff"]}}
这使用Hash#update(也称为merge!
)的形式,它采用一个块来确定两个合并的哈希中存在的键的值,这里的键是1
和2
。该块具有三个块变量:_
等于公共密钥 1 ; o
(“旧”)是正在构造的哈希中的键_
的值,而n
(“ new”)是哈希中的键_
的值被合并到正在构建的哈希中。
如果[*o[:second_hash_key]]
不是数组,则表达式o[:second_hash_key]
会将o[:second_hash_key]
转换为自身的数组,如果已经是数组,则将o[:second_hash_key]
保留不变。例如[*1] #=> [1]
,而[*[1,2]] #=> [1,2]
。
返回值存在问题,因为:second_hash_key
的值在一种情况下是一个数组数组,而在另一种情况下,它只是一个数组。因此,在随后的计算中,有必要确定每个值是数组的数组还是仅仅是数组,然后相应地采取措施。当然可以做到这一点,但是它是凌乱和丑陋的。最好使所有的值数组组成数组。我们可以这样做,如下。
my_array.each_with_object({}) do |g,h|
h.update(g[:first_hash_key][:id]=>
g.merge(second_hash_key: [g[:second_hash_key]])) { |_,o,n|
o.merge(second_hash_key: o[:second_hash_key] + n[:second_hash_key]) }
end.values
#=> [{:first_hash_key=>{:id=>1, :title=>"my title"},
# :second_hash_key=>[["stuff", "more stuff", "more stuff"],
# ["stuff 3", "uniq stuff 2"]]},
# {:first_hash_key=>{:id=>2, :title=>"my other title"},
# :second_hash_key=>[["interesting stuff", "uniq stuff"]]}]
1下划线(有效的局部变量)用于公用密钥的作用是告知读者,块计算中未使用该下划线。