Код
def convert(h)
h.each_with_object(Hash.new { |e,k| e[k]={} }) do |(date, v),f|
v.each { |g| f[date].update(g) { |_,ov,nv|ov.is_a?(Array) ? ov+nv : ov } }
end
end
Пример
Из-за большого размера и форматирования примера трудно распознать лес за деревьями. Первое, что я сделал, это свел пример с его основной структурой. Я сократил количество ключей (строк даты) с трех до двух и уменьшил количество ключей в каждом хеше. Я также использовал отступы для уточнения структуры. Таким образом я получил следующее.
h = {
"2015-05-15"=>[
{ "minutes"=>25,
"key1"=>[{ "some key1"=>"14", "some key"=>"subject here" }],
"key2"=>[{ "some key"=>"5/5"}],
"key5"=>"2015-05-15"
},
{ "minutes"=>25,
"key1"=>[{ "some key1"=>"14", "some key"=>"subject here" }],
"key2"=>[{ "some key"=>"5/5" }],
"key4"=>[{ "some key"=>"0.6" }],
"key5"=>"2015-05-15"
}
],
"2015-06-10"=>[
{ "minutes"=>25,
"key1"=>[{ "some key1"=>"14", "some key"=>"subject here" }],
"key2"=>[{ "some key"=>"5/5" }],
"key5"=>"2015-06-10"
},
{ "minutes"=>25,
"key1"=>[{ "some key1"=>"14", "some key"=>"subject here" }],
"key2"=>[{ "some key"=>"5/5"}]
}
]
}
convert(h)
#=> { "2015-05-15"=>{
# "minutes"=>25,
# "key1"=>[{"some key1"=>"14", "some key"=>"subject here"},
# {"some key1"=>"14", "some key"=>"subject here"}],
# "key2"=>[{"some key"=>"5/5"},
# {"some key"=>"5/5"}],
# "key5"=>"2015-05-15",
# "key4"=>[{"some key"=>"0.6"}]},
# "2015-06-10"=>{
# "minutes"=>25,
# "key1"=>[{"some key1"=>"14", "some key"=>"subject here"},
# {"some key1"=>"14", "some key"=>"subject here"}],
# "key2"=>[{"some key"=>"5/5"},
# {"some key"=>"5/5"}],
# "key5"=>"2015-06-10"
# }
# }
Этот результат немного отличается от того, что было запрошено. Значение каждого ключа строки даты (например, "2015-05-15"
) должно было быть массивом, содержащим один элемент (хеш). Нет смысла иметь массивы, которые всегда содержат один элемент, поэтому я упростил создание значений хешей строк даты.
Объяснение
Hash.new { |h,k| h[k]={} }
приводит к тому, что h[k]
устанавливается равным пустому хэшу, когда h
не имеет ключа k
. Смотрите форму Hash :: new , в которой используется блок.
Я использовал форму Hash # update (a.k.a. merge!) that employs a block to determine the values of keys that are present in both hashes being merged. See the doc for the values of the three block variables,
k (common key),
ov ("*old value*") and
nv` (" new value ")
Код более или менее эквивалентен следующему.
f = {}
h.each do |date, v|
v.each do |g|
f[date] = {} unless f.key?(date)
f[date].update(g) { |_,ov,nv| ov.is_a?(Array) ? ov+nv : ov }
end
end
f
Если это все еще не ясно, попробуйте запустить этот код с добавлением некоторых операторов puts
.
f = {}
h.each do |date, v|
puts "date=#{date}"
puts "v=#{v}"
puts "f=#{f}"
v.each do |g|
puts " f=#{g}"
if f.key?(date)
puts " f has key date=#{date} so f[#{date}] is not set to {}"
else
puts " f does not has key date=#{date} so f[#{date}] is to {}"
end
f[date] = {} unless f.key?(date)
f[date].update(g) { |_,ov,nv| ov.is_a?(Array) ? ov+nv : ov }
puts " f[#{date}]= #{f[date]}"
end
end
f
Это печатает следующее.
date=2015-05-15
v=[{"minutes"=>25, "key1"=>[{"some key1"=>"14", "some key"=>"subject here"}],
"key2"=>[{"some key"=>"5/5"}], "key5"=>"2015-05-15"},
{"minutes"=>25, "key1"=>[{"some key1"=>"14", "some key"=>"subject here"}],
"key2"=>[{"some key"=>"5/5"}], "key4"=>[{"some key"=>"0.6"}],
"key5"=>"2015-05-15"}]
f={}
f={"minutes"=>25, "key1"=>[{"some key1"=>"14", "some key"=>"subject here"}],
"key2"=>[{"some key"=>"5/5"}], "key5"=>"2015-05-15"}
f does not has key date=2015-05-15 so f[2015-05-15] is to {}
f[2015-05-15]= {"minutes"=>25,
"key1"=>[{"some key1"=>"14", "some key"=>"subject here"}],
"key2"=>[{"some key"=>"5/5"}], "key5"=>"2015-05-15"}
f={"minutes"=>25, "key1"=>[{"some key1"=>"14", "some key"=>"subject here"}],
"key2"=>[{"some key"=>"5/5"}],
"key4"=>[{"some key"=>"0.6"}],
"key5"=>"2015-05-15"}
f has key date=2015-05-15 so f[2015-05-15] is not set to {}
f[2015-05-15]= {"minutes"=>25,
"key1"=>[{"some key1"=>"14", "some key"=>"subject here"},
{"some key1"=>"14", "some key"=>"subject here"}],
"key2"=>[{"some key"=>"5/5"},
{"some key"=>"5/5"}],
"key5"=>"2015-05-15",
"key4"=>[{"some key"=>"0.6"}]}
date=2015-06-10
v=[{"minutes"=>25,
"key1"=>[{"some key1"=>"14", "some key"=>"subject here"}],
"key2"=>[{"some key"=>"5/5"}],
"key5"=>"2015-06-10"},
{"minutes"=>25,
"key1"=>[{"some key1"=>"14", "some key"=>"subject here"}],
"key2"=>[{"some key"=>"5/5"}]}]
f={"2015-05-15"=>{"minutes"=>25,
"key1"=>[{"some key1"=>"14", "some key"=>"subject here"},
{"some key1"=>"14", "some key"=>"subject here"}],
"key2"=>[{"some key"=>"5/5"},
{"some key"=>"5/5"}],
"key5"=>"2015-05-15",
"key4"=>[{"some key"=>"0.6"}]}}
f={"minutes"=>25,
"key1"=>[{"some key1"=>"14", "some key"=>"subject here"}],
"key2"=>[{"some key"=>"5/5"}],
"key5"=>"2015-06-10"}
f does not has key date=2015-06-10 so f[2015-06-10] is to {}
f[2015-06-10]= {"minutes"=>25,
"key1"=>[{"some key1"=>"14", "some key"=>"subject here"}],
"key2"=>[{"some key"=>"5/5"}], "key5"=>"2015-06-10"}
f={"minutes"=>25,
"key1"=>[{"some key1"=>"14", "some key"=>"subject here"}],
"key2"=>[{"some key"=>"5/5"}]}
f has key date=2015-06-10 so f[2015-06-10] is not set to {}
f[2015-06-10]= {"minutes"=>25,
"key1"=>[{"some key1"=>"14", "some key"=>"subject here"},
{"some key1"=>"14", "some key"=>"subject here"}],
"key2"=>[{"some key"=>"5/5"}, {"some key"=>"5/5"}],
"key5"=>"2015-06-10"}