Reputation: 27852
I have an array of Users, and each User responds to a method called houses that return all the houses of the users. I want to have an array of hashes with users name and houses color name, so here is what I have:
[user1, user2, user3].flat_map do |user|
user.houses.map do |house|
create_user_house(user, house)
end
end
def create_user_house(user, house)
{name: user.name, house: find_color(house)}
end
Is there any better way of doing this? I have a feeling that using flat_map
might be overkill in this situation
EXAMPLE:
Say I have two users:
user_1 which name is 'John'
user_1 has two houses: house_1 and house_2
user_2 which name is 'Steve'
user_2 has one house: house_3
The expected result should be:
[{name: 'John', house_color: find_color(house1)}, {name: 'John', house_color: find_color(house2)}, {name: 'Steve', house_color: find_color(house3)}]
Upvotes: 0
Views: 527
Reputation: 110685
Let's have some data to work with:
class User
attr_accessor :name, :houses
def initialize name, houses
@name = name
@houses = houses
end
end
wilma = User.new 'Wilma', [:bungalow, :cottage]
hank = User.new 'Hank', [:cape_cod, :bungalow]
oaf = User.new 'Oaf', [:shed, :cottage]
def find_color(h)
case h
when :bungalow then :yellow
when :cottage then :blue
when :cape_cod then :white
when :shed then :black
end
end
You approach is fine, but I'm not sure you need the separate method. Without it, it's:
[wilma, hank, oaf].flat_map do |user|
user.houses.map { |h| { name: user.name, house_color: find_color(h) } }
end
#=> [{:name=>"Wilma", :house_color=>:yellow},
# {:name=>"Wilma", :house_color=>:blue},
# {:name=>"Hank", :house_color=>:white},
# {:name=>"Hank", :house_color=>:yellow},
# {:name=>"Oaf", :house_color=>:black},
# {:name=>"Oaf", :house_color=>:blue}]
I think flat_map
is quite appropriate here.
You could write it many other ways, of course, one being:
[wilma, hank, oaf].each_with_object([]) do |user, a|
user.houses.each { |h| a << { name: user.name, house_color: find_color(h) } }
end
Upvotes: 1