Вы можете изменить свой код следующим образом:
bb = b.select { |f| a.any? { |h| h[:umc] == f[:umc] } }
#=> [{:umc=>"11VE", :code=>"23"},
# {:umc=>"1140", :code=>"44"},
# {:umc=>"1973", :code=>"55"}]
(a + bb).group_by { |g| g[:umc] }.map { |_,v| v.reduce(:merge) }
#=> [{:umc=>"11VE", :title=>"FOOBARS", :code=>"23"},
# {:umc=>"1973", :title=>"ZOOBARS", :code=>"55"},
# {:umc=>"1140", :title=>"TINYBAR", :code=>"44"}]
, но это было бы более эффективным для расчета bb
таким образом:
require 'set'
umc_a_vals = a.map { |g| g[:umc] }.to_set
#=> #<Set: {"11VE", "1973", "1140"}>
bb = b.select { |f| umc_a_vals.include(f[:umc]) }
#=> [{:umc=>"11VE", :code=>"23"},
# {:umc=>"1140", :code=>"44"},
# {:umc=>"1973", :code=>"55"}]
Вот еще один способ:
f = a.group_by { |g| g }.map { |_,v| v.reduce(:merge) }
#=> [{:umc=>"11VE", :title=>"FOOBARS"},
# {:umc=>"1973", :title=>"ZOOBARS"},
# {:umc=>"1140", :title=>"TINYBAR"}]
b.each_with_object(f) do |g,h|
(h.update(g[:umc]=>g) { |_,o,n| o.merge(n) }) if h.key?(g[:umc])
end.values
#=> [{:umc=>"11VE", :title=>"FOOBARS", :code=>"23"},
# {:umc=>"1973", :title=>"ZOOBARS", :code=>"55"},
# {:umc=>"1140", :title=>"TINYBAR", :code=>"44"}]
Расчет f
настолько похож на ваш код, что я не считаю необходимым объяснение.
теперь объединить хэш:
{ g[:umc]=g }
#=> { "11VE"=>{:umc=>"11VE", :code=>"23"} }
в h
если h
имеет ключевое "11VE"
, что она делает. Для этого мы используем форму Hash#update (А.К.А. merge!
), который использует блок:
{ |_,o,n| o.merge(n) }
для определения значений ключей, которые присутствуют в обоих хешей быть объединены.
Переменные блока равны:
_ #=> "11VE"
o #=> {:umc=>"11VE", :title=>"FOOBARS"}
n #=> {:umc=>"11VE", :code=>"23"}
поэтому результат расчета блока является:
o.merge(n)
#=> {:umc=>"11VE", :title=>"FOOBAR, :code=>"23"}
, который является обновленной значение h[:umc]
.
Кроме того: я использовал локальную переменную _
для значения ключа, чтобы обратить внимание на то, что он не используется при расчете блока. Переменные o
и n
обычно используются для представления «старых» и «новых» значений, соответственно.
Объединение в h
хешей, построенных из оставшихся значений b
, производится аналогичным образом.
Последним шагом является извлечение значений h
.
В качестве второго примера, предположим, что:
a = [
{:umc=>"11VE", :title=>"FOOBARS"},
{:umc=>"11VE", :title=>"ZOOBARS", :author=>"Billy-Bob"},
{:umc=>"1140", :title=>"TINYBAR"}
]
Получаем:
f = a.each_with_object({}) { |g,h| h.update(g[:umc]=>g) { |_,o,n| o.merge(n) } }
#=> {"11VE"=>{:umc=>"11VE", :title=>"ZOOBARS", :author=>"Billy-Bob"},
# "1140"=>{:umc=>"1140", :title=>"TINYBAR"}}
b.each_with_object(f) do |g,h|
(h.update(g[:umc]=>g) { |_,o,n| o.merge(n) }) if h.key?(g[:umc])
end.values
#=> [{:umc=>"11VE", :title=>"ZOOBARS", :author=>"Billy-Bob", :code=>"23"},
# {:umc=>"1140", :title=>"TINYBAR", :code=>"44"}]
Как насчет ': УМС => "10EE"'? – falsetru
Извините, что 10EE не должен появляться в первом массиве. Излишне говорить, что фактические данные имеют более 10 000 наименований. Спасибо за уловку. – berlin