Добавьте ha sh в массив, если ha sh с этим значением не существует, в противном случае расширьте существующий - PullRequest
2 голосов
/ 25 мая 2020

Я хочу создать массив с ролями для проектов. У меня есть массив хэшей, например:

projects_with_roles =
[
  { id: 1, name: 'First', roles: ['user', 'compliance_lead'] },
  { id: 5, name: 'Five', roles: ['financial_lead'] }
]

Я хочу добавить роль в массив ролей, если ha sh с идентификатором проекта уже существует, в противном случае - добавить новый ha sh.

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

Как я могу это сделать?

Ответы [ 3 ]

2 голосов
/ 25 мая 2020

Это обычный сценарий ha sh reduce. Что вы можете сделать, так это объединить (суммировать) оба массива и сгруппировать их по их идентификатору, после чего вы можете сопоставить результат и уменьшить значения ha sh, объединяя их и создавая один массив из их ролей:

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 голосов
/ 25 мая 2020

Вам нужно найти элемент с таким же 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 голос
/ 25 мая 2020
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 равным вышеуказанному вычислению.

Здесь используется форма Hash # update (также известная как merge!), которая использует блок { |_,o,n| o|n } для определения значения ключей, которые присутствуют в обоих сливаемых хэшах. См. Do c для объяснения значений трех переменных блока (_, 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"]} 

Путем построения ha sh и последующего преобразования его в массив хэшей вычислительная сложность сохраняется почти на уровне O(projects_with_roles.size + projects_to_add.size), поскольку поиск ключей ha sh близок к O(1).

...