如果不存在该值的哈希,则在数组中添加哈希,否则扩展现有的哈希。

问题描述 投票:0回答:1

我想为项目创建一个包含角色的数组,我有一个哈希数组,就像这样。

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'] }
]

我怎样才能做到这一点?

arrays ruby-on-rails ruby hash ruby-hash
1个回答
2
投票

这是一个常见的哈希还原方案。你可以做的是将两个数组进行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"]}]

2
投票

你需要找到具有相同 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

这个运算符 |= 只有当数组中没有新的值时,才会向数组中添加新的值。它使我们能够避免在角色列表中添加重复的值。


1
投票
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 } 来确定被合并的两个哈希中的键值。请参阅文档以了解关于块的三个块变量的值的解释 (_, on). (我用下划线来表示第一个,也就是普通键,表示它不用于块计算。

请注意,中间的计算过程如下。

(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).

© www.soinside.com 2019 - 2024. All rights reserved.