我有这样的数据格式,数组a
:
[{
agreement_id: 1,
app_user_id: 1,
agency_name: 'Small business 1'
},
{
agreement_id: 1,
app_user_id: 2,
agency_name: 'Small business 1'
},
{
agreement_id: 2,
app_user_id: 1,
agency_name: 'Small business 2'
}]
我显然简化了数组元素,实际上我有列表或AR对象,但它的要点应该是相同的。
我基本上希望创建一个用户协议地图。我的意思是这个输出:
[{
agreement_id: 1,
app_users: [1, 2],
agency_name: 'Small business 1'
},
{
agreement_id: 2,
app_user_id: [1],
agency_name: 'Small business 2'
}]
这就是我想要的方式(伪代码):
h
b
a
elem
),检查h
是否没有elem[:agreement_id]
键,然后在名为elem
的{{1}}上创建新属性并将app_users
作为值放在新属性中(一个值的数组)。 然后将没有[elem[: app_user_id]]
属性的elem
推送到数组b。
然后我们迭代下一个元素app_user_id
,如果它没有elem
键,我们就会做同样的事情。
但是,如果elem[:agreement_id]
具有h
键,请将elem[:agreement_id]
附加到elem[: app_user_id]
属性数组。然后将没有app_users
属性的elem
推送到数组b。
是否有更简便的方法来完成同样的事情,更多内联现有的ruby方法?
答案 0 :(得分:3)
group_by
,values_at
和map
混合可以让您更接近目标。
此代码组将agreement_id
和agency_name
的值具有相同的哈希值。
即使数组包含一个元素,并且第一个:app_user_ids
已重命名为customer_name
,输出键始终为agency_name
:
data = [{
agreement_id: 1,
app_user_id: 1,
agency_name: 'Small business 1'
},
{
agreement_id: 1,
app_user_id: 2,
agency_name: 'Small business 1'
},
{
agreement_id: 2,
app_user_id: 1,
agency_name: 'Small business 2'
}]
puts data.group_by{ |hash|
hash.values_at(:agreement_id, :agency_name)
}.map{ |(agreement_id, agency_name), hashes|
{
agreement_id: agreement_id,
agency_name: agency_name,
app_user_ids: hashes.map { |h| h[:app_user_id] }
}
}
# {:agreement_id=>1, :agency_name=>"Small business 1", :app_user_ids=>[1, 2]}
# {:agreement_id=>2, :agency_name=>"Small business 2", :app_user_ids=>[1]}
答案 1 :(得分:0)
我假设(与其他人一样)OP示例中的键:customer_name
应为:agency_name
,并且:agency_name
的值对于具有相同值的所有哈希值都相同:agreement_id
。
h = [{
agreement_id: 1,
app_user_id: 1,
agency_name: 'Small business 1'
},
{
agreement_id: 1,
app_user_id: 2,
agency_name: 'Small business 1'
},
{
agreement_id: 2,
app_user_id: 1,
agency_name: 'Small business 2'
}]
h.each_with_object({}) do |g,h|
h.update(g[:agreement_id]=>{ agreement_id: g[:agreement_id],
app_user_id: [g[:app_user_id]],
agency_name: g[:agency_name]
}
) do |_,o,n| { agreement_id: o[:agreement_id],
app_user_id: o[:app_user_id] + n[:app_user_id],
agency_name: o[:agency_name]
}
end
end.values
#=> [{:agreement_id=>1, :app_user_id=>[1, 2], :agency_name=>"Small business 1"},
# {:agreement_id=>2, :app_user_id=>[1], :agency_name=>"Small business 2"}]
这使用Hash#update(aka merge!
)的形式,它使用一个块来计算两个哈希值中合并的键值。有关进一步说明,请参阅文档,特别是每个块的三个键的内容。 (我使用下划线表示第一个键 - 公共键 - 表示它没有在块计算中使用。)
答案 2 :(得分:0)
谢谢大家的回答,我同时做到了这一点,我没有看到回复。这是我的解决方案:
json_map = {}
[{
agreement_id: 1,
app_user_id: 1,
agency_name: 'Small business 1'
},
{
agreement_id: 1,
app_user_id: 2,
agency_name: 'Small business 1'
},
{
agreement_id: 2,
app_user_id: 1,
agency_name: 'Small business 2'
}].each do |ag_deal|
app_user_id = ag_deal[:app_user_id]
agreement_id = ag_deal[:agreement_id]
if json_map.key?(agreement_id)
ag_deal = json_map[agreement_id]
ag_deal[:app_user_ids] << app_user_id
else
ag_deal[:app_user_ids] = [app_user_id]
json_map[agreement_id] = ag_deal.except(:app_user_id)
end
end
所以期望的结果是json_map.values
,粘贴:
[
{:agreement_id=>1, :agency_name=>"Small business 1", :app_user_ids=>[1, 2]},
{:agreement_id=>2, :agency_name=>"Small business 2", :app_user_ids=>[1]}
]
我将对这些进行基准测试并使用最快的一个,我将在数组中创建一个包含几个随机用户的1000个项目,希望能够正确模拟它。
以下是我的基准测试结果:
=======Cary ======
user system total real
0.010000 0.000000 0.010000 ( 0.008853)
=====Eric====
user system total real
0.020000 0.010000 0.030000 ( 0.017856)
====me=====
user system total real
0.010000 0.030000 0.040000 ( 0.020826)
这是样本数据的生成方式:
users = [1, 2, 3, 4, 5]
data = []
1000.times do |i|
data << {
agreement_id: i,
app_user_id: users.shuffle.first,
agency_name: "Small business #{i}"
}
end