Ты почти у цели, просто нужна была тонкая настройка:
def merge_data(keys, data)
merged_data = keys.map {|hash| data.first.map {|k,v| if hash.values.first == k then hash.merge(v) end }.compact[0] }
end
keys = [{:first_name => "blake"}, {:first_name => "ashley"}]
data = [
{"blake" => {
:awesomeness => 10,
:height => "74",
:last_name => "johnson"},
"ashley" => {
:awesomeness => 9,
:height => 60,
:last_name => "dubs"}
}]
puts merge_data(keys, data).inspect
#=>
[
{
:first_name=>"blake",
:awesomeness=>10,
:height=>"74",
:last_name=>"johnson"},
{
:first_name=>"ashley",
:awesomeness=>9,
:height=>60,
:last_name=>"dubs"
}
]
Что изменилось ??
Добавлено .compact[0]
во внутренний блок.
Почему?Потому что это map
, работающий на каждом ключе и каждом значении данных.Возвращая nil для одного, который не совпадает с другим, и возвращая массив каждый раз вместо Hash
объекта.
Однако мы можем создать собственный класс и восстановить данные позже:
class Person
attr_reader :first_name, :last_name, :height, :awesomeness
def initialize(first_name)
@first_name = first_name
end
def update(info)
info.each do |key, value|
instance_variable_set("@#{key}", value) if respond_to?(key)
end
end
def to_h
{ first_name: self.first_name, last_name: self.last_name, awesomeness: self.awesomeness, height: self.height }
end
end
people = keys.each_with_object({}) do |k, person_map|
person_map[k[:first_name]] = Person.new(k[:first_name])
end
data.each do |people_info|
people_info.each do |first_name, info|
if people[first_name]
people[first_name].update(info)
end
end
end
p people.values.map{ |p| p.to_h }
#=> [{:first_name=>"blake", :last_name=>"johnson", :awesomeness=>10, :height=>"74"}, {:first_name=>"ashley", :last_name=>"dubs", :awesomeness=>9, :height=>60}]