mbb
mbb

Reputation: 3110

Using Enumerables across multiple objects in Ruby

I'm playing around with Ruby on Codecademy and not sure how to reduce this further. Current code is:

group_1 = [4.1, 5.5, 3.2, 3.3, 6.1, 3.9, 4.7]
group_2 = [7.0, 3.8, 6.2, 6.1, 4.4, 4.9, 3.0]
group_3 = [5.5, 5.1, 3.9, 4.3, 4.9, 3.2, 3.2]

over_4_feet = Proc.new { |height| height >= 4 }

can_ride_1 = group_1.select(&over_4_feet)
can_ride_2 = group_2.select(&over_4_feet)
can_ride_3 = group_3.select(&over_4_feet)

I wonder how I could get to something like this:

can_ride_(1..3).each {|x| group_(x).select(&over_4_feet)}

Is it possible, when objects hold repeatable patterns like these do, to use an Enumerable method in this way? I don't mind if it's a regex, but curious about what pattern might be recommended.

Upvotes: 3

Views: 71

Answers (2)

coreyward
coreyward

Reputation: 80041

This is a really crappy question (the one on CodeAcademy) because the code blatantly doesn't represent the real world. It's contrived to the point that defining objects around the behavior is challenging. That said, here's another approach that's purely academic — don't ever do this in production code:

group_1 = …
group_2 = …
group_3 = …

can_ride_1 = can_ride_2 = can_ride_3 = nil

1.upto(3) do |i|
  group = binding.local_variable_get("group_#{i}")
  binding.local_variable_set("can_ride_#{i}", group.select { |v| v >= 4 })
end

Here's another exploitation of this:

eligible_riders = -> (group_num) do
  group = binding.local_variable_get("group_#{group_num}")
  group.select { |v| v >= 4 }
end

can_ride_1 = eligible_riders[1]
can_ride_2 = eligible_riders[2]
can_ride_3 = eligible_riders[3]

A more appropriate way of doing this would be to extract an object to represent each group:

class Group < Array
  def select_eligible
    select { |v| v >= 4 }
  end
end

group_1 = Group.new [1, 2, 3, 4, 5]
group_2 = Group.new [1, 2, 3, 4, 5]
group_3 = Group.new [1, 2, 3, 4, 5]

eligible = [group_1, group_2, group_3].map &:select_eligible
can_ride_1, can_ride_2, can_ride_3 = *eligible

Or you can take advantage of those splat enhancements using the proc you have:

can_ride_1, can_ride_2, can_ride_3 = *[group_1, group_2, group_3].map do |g|
  g.select &over_4_feet
end

Upvotes: 1

Gabriel
Gabriel

Reputation: 1942

Instead of having a variable for each group, you can have an array of groups, so you can map it to another array applying your select in each element.

groups = []

groups.push [4.1, 5.5, 3.2, 3.3, 6.1, 3.9, 4.7]
groups.push [7.0, 3.8, 6.2, 6.1, 4.4, 4.9, 3.0]
groups.push [5.5, 5.1, 3.9, 4.3, 4.9, 3.2, 3.2]

over_4_feet = Proc.new { |height| height >= 4 }

can_ride = groups.map { |group| group.select(&over_4_feet) }

puts can_ride

Upvotes: 1

Related Questions