I’m trying to find the best way to refactor iterating over this array and converting it into an array of new objects. The beans_to_build array is an array of objects that has a property of count which tells you how many new instances of the object to create with a set of properties. I’m looking to return an array of all the new JellyBean objects preferably without having to store them in the new_beans array
def new_jelly_beans
beans_to_build.inject([]) do |memo, bean_to_build|
memo << JellyBean.new(prop1: bean_to_build.prop1, prop2: btb.prop2)
end
end
``
If you give the class that a “bean to build” is a method that can return a set of parameters (prop1, prop2) as a hash, then you could make that code even more straightforward.
You can use Enumerable’s map to return a new array. Your code can be rewritten as:
def new_jelly_beans
new_beans = beans_to_build.map do |btb|
btb.count.times.map do
JellyBean.new(prop1: btb.prop1, prop2: btb.prop2)
end
end
new_beans.flatten
end
There’s a lot being done here… after a refactor:
def new_jelly_beans
# we want an array of all the beans, not an array of arrays
new_beans(beans_to_build).flatten
end
private
def new_beans(beans_to_build)
# map over each bean_building_template and build an array of beans
beans_to_build.map do |bean_building_template|
build_beans(bean_building_template)
end
end
def build_beans(bean_building_template)
# build an array of beans from a bean building template
bean_building_template.count.times.map do
JellyBean.new(prop1: bean_building_template.prop1, prop2: bean_building_template.prop2)
end
end
I’ve changes some of the names to be clearer on what they do… ideally you don’t want any comments in your code, it should be clear what your doing from the names.
Hope that helps. There is also a collect method that is identical to map. I tend to always use map but I know some developers prefer to use collect when building an array.
Another way using inject:
def new_jelly_beans
beans_to_build.inject([]) do |result, bean_building_template|
result + bean_array(bean_building_template)
end
end
def bean_array(bean_building_template)
Array.new(bean_building_template.count) { JellyBean.new(prop1: bean_building_template.prop1, prop2: bean_building_template.prop2 }
end
When using that approach all objects of the final array will be identical, though. This might lead to surprising behavior once you start mutating these objects.