Нам дано следующее (упрощено из массивов, приведенных в вопросе и с одним хешем, добавленным к arr2
):
arr1 = [
{"Date"=>"2019-07-01", "Country"=>"US", "Price"=>"11.22", "Tax"=>"8.55"},
{"Date"=>"2019-07-01", "Country"=>"US", "Price"=>"16.66", "Tax"=>"6.55"},
{"Date"=>"2019-06-30", "Country"=>"US", "Price"=>"17.85", "Tax"=>"7.12"},
{"Date"=>"2019-07-02", "Country"=>"UK", "Price"=>"14.22", "Tax"=>"4.32"}
]
arr2 = [
{"Date"=>"2019-07-01", "Price"=>"11.34", "Tax"=>"3.44"},
{"Date"=>"2019-07-01", "Price"=>"14.33", "Tax"=>"5.41"},
{"Date"=>"2019-07-02", "Price"=>"10.22", "Tax"=>"2.34"},
{"Date"=>"2019-07-03", "Price"=>"14.67", "Tax"=>"3.14"}
]
Нам потребуется список дат со значениями "Date"
в хешах arr1
.
dates1 = arr1.map { |g| g["Date"] }.uniq
#=> ["2019-07-01", "2019-06-30", "2019-07-02"]
Теперь преобразуйте arr2
в массив этих элементов h
в arr2
, для которых h["Date"]
находится в dates1
со всеми ключами, отличными от "Price"
и "Tax"
, удаленными из каждого сохраненного хеша, и со значениями этих двух ключей, преобразованными в строковые представления их значений, аннулированы:
a2 = arr2.each_with_object([]) do |g,arr| arr <<
{ "Date"=>g["Date"], "Price"=>"-" << g["Price"], "Tax" =>"-" << g["Tax"] } if
dates1.include?(g["Date"])
end
#=> [{"Date"=>"2019-07-01", "Price"=>"-11.34", "Tax"=>"-3.44"},
# {"Date"=>"2019-07-01", "Price"=>"-14.33", "Tax"=>"-5.41"},
# {"Date"=>"2019-07-02", "Price"=>"-10.22", "Tax"=>"-2.34"}]
Теперь мы перебираем все элементы arr1
и a2
, чтобы создать хеш с ключами значений "Date"
, со значениями "Price"
и "Tax"
агрегированными. После этого мы извлекаем значение созданного хеша.
(arr1 + a2).each_with_object({}) do |g,h|
h.update(g["Date"]=>g) do |_,merged_hash,hash_to_merge|
merged_hash.merge(hash_to_merge) do |k,merged_str,str_to_merge|
["Price", "Tax"].include?(k) ? "%.2f" %
(merged_str.to_f + str_to_merge.to_f) : merged_str
end
end
end.values
#=> [{"Date"=>"2019-07-01", "Country"=>"US", "Price"=>"2.21", "Tax"=>"6.25"},
# {"Date"=>"2019-06-30", "Country"=>"US", "Price"=>"17.85", "Tax"=>"7.12"},
# {"Date"=>"2019-07-02", "Country"=>"UK", "Price"=>"4.00", "Tax"=>"1.98"}]
На этом последнем шаге получатель values
считается хешем:
{"2019-07-01"=>{"Date"=>"2019-07-01", "Country"=>"US",
"Price"=>"2.21", "Tax"=>"6.25"},
"2019-06-30"=>{"Date"=>"2019-06-30", "Country"=>"US",
"Price"=>"17.85", "Tax"=>"7.12"},
"2019-07-02"=>{"Date"=>"2019-07-02", "Country"=>"UK",
"Price"=>"4.00", "Tax"=>"1.98"}}
Обратите внимание, что результат будет таким же, если arr[1]["Country"]=>"Canada"
. Я предположил, что это не будет проблемой или не может произойти.
На последнем шаге используются версии методов Hash # update (он же merge!
) и Hash # merge , которые используют хеш для определения значений ключей, присутствующих в оба хеша объединяются.
Значения блочных переменных (|_,merged_hash,hash_to_merge|
и |k,merged_str,str_to_merge|
) объяснены в документации. Первая переменная блока - это общий ключ (_
и k
). Я представил первый из них с подчеркиванием, чтобы показать читателю, что он не используется в вычислениях блоков (общее соглашение). Вторая переменная блока - это значение ключа в строящемся хеше (merged_hash
и merged_str
). Третья переменная блока - это значение ключа в объединяемом хэше (merged_hash
и str_to_merge
).