我想为项目创建一个包含角色的数组,我有一个哈希数组,就像这样。
projects_with_roles =
[
{ id: 1, name: 'First', roles: ['user', 'compliance_lead'] },
{ id: 5, name: 'Five', roles: ['financial_lead'] }
]
我想把角色添加到角色数组中, 如果项目ID的哈希已经存在, 否则 - 添加新的哈希.
projects_with_roles << { id: 5, name: 'Five', roles: ['technical_lead'] }
projects_with_roles << { id: 10, name: 'Ten', roles: ['user'] }
projects_with_roles =
[
{ id: 1, name: 'First', roles: ['user', 'compliance_lead'] },
{ id: 5, name: 'Five', roles: ['financial_lead', 'technical_lead'] },
{ id: 10, name: 'Ten', roles: ['user'] }
]
我怎样才能做到这一点?
这是一个常见的哈希还原方案。你可以做的是将两个数组进行concat(sum),并按其id进行分组,之后你可以将结果进行映射并减少哈希值,将它们合并,并从它们的角色中制作一个数组。
projects_with_roles = [{ id: 1, name: 'First', roles: ['user', 'compliance_lead'] }, { id: 5, name: 'Five', roles: ['financial_lead'] }]
roles = [{ id: 5, name: 'Five', roles: ['technical_lead'] }, { id: 10, name: 'Ten', roles: ['user'] }]
(projects_with_roles + roles)
.group_by { |e| e[:id] }
.map do |_, val|
val.reduce({}) do |x, y|
x.merge(y) do |key, oldval, newval|
key == :roles ? oldval + newval : oldval
end
end
end
# [{:id=>1, :name=>"First", :roles=>["user", "compliance_lead"]},
# {:id=>5, :name=>"Five", :roles=>["financial_lead", "technical_lead"]},
# {:id=>10, :name=>"Ten", :roles=>["user"]}]
你需要找到具有相同 id
并更改角色列表或添加新项目。这里是简化的解决方案。
projects_with_roles = [
{ id: 1, name: 'First', roles: ['user'] },
{ id: 5, name: 'Five', roles: ['financial_lead', 'technical_lead'] },
]
new_project = { id: 5, name: 'Five', roles: ['user'] }
project = projects_with_roles.find { |project| project[:id] == new_project[:id] }
if project
project[:roles] |= new_project[:roles]
else
projects_with_roles << new_project
end
这个运算符 |=
只有当数组中没有新的值时,才会向数组中添加新的值。它使我们能够避免在角色列表中添加重复的值。
projects_with_roles = [
{ id: 1, name: 'First', roles: ['user', 'compliance_lead'] },
{ id: 5, name: 'Five', roles: ['financial_lead'] }
]
projects_to_add = [
{ id: 5, name: 'Five', roles: ['technical_lead'] },
{ id: 10, name: 'Ten', roles: ['user'] }
]
(projects_with_roles + projects_to_add).each_with_object({}) do |g,h|
h.update([g[:id], g[:name]]=>g[:roles]) { |_,o,n| o|n }
end.map { |(id,name),roles| { id: id, name: name, roles:roles } }
#=> [{:id=>1, :name=>"First", :roles=>["user", "compliance_lead"]},
# {:id=>5, :name=>"Five", :roles=>["financial_lead", "technical_lead"]},
# {:id=>10, :name=>"Ten", :roles=>["user"]}]
这不会使 projects_with_roles
. 如果需要,请设置 projects_with_roles
等于上述计算。
这使用的形式是 散列值#更新 (又名 merge!
),它采用的是块 { |_,o,n| o|n }
来确定被合并的两个哈希中的键值。请参阅文档以了解关于块的三个块变量的值的解释 (_
, o
和 n
). (我用下划线来表示第一个,也就是普通键,表示它不用于块计算。
请注意,中间的计算过程如下。
(projects_with_roles + projects_to_add).each_with_object({}) do |g,h|
h.update([g[:id], g[:name]]=>g[:roles]) { |_,o,n| o|n }
end
#=> {[1, "First"]=>["user", "compliance_lead"],
# [5, "Five"]=>["financial_lead", "technical_lead"],
# [10, "Ten"]=>["user"]}
通过建立一个哈希值 然后将其转换为一个哈希数组 计算的复杂度被控制在近似于 O(projects_with_roles.size + projects_to_add.size)
由于哈希键查找接近于 O(1)
.