Hommer Smith
Hommer Smith

Reputation: 27852

Better way than flat_map to iterate over data structure

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

Answers (1)

Cary Swoveland
Cary Swoveland

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

Related Questions