3

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.

5
  • have you looked at .send stackoverflow.com/questions/5349624/… Commented Feb 19, 2017 at 21:42
  • I think dynamic dispatch is what you are looking for ... Commented Feb 19, 2017 at 21:44
  • @mahatmanich doesn't group_#{x} work ? I remember seeing this # somewhere Commented Feb 19, 2017 at 21:49
  • Actually .call .send .eval are doing similar things => blog.khd.me/ruby/ruby-dynamic-method-calling Commented Feb 19, 2017 at 21:51
  • @niceman no it does not, it will only do string interpolation, but will return a string. "group_#{x}" will return "group_1", "group_2" but will only return a string. send("group_#{x}") on the other hand should work! Commented Feb 19, 2017 at 22:00

2 Answers 2

1

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
Sign up to request clarification or add additional context in comments.

1 Comment

Yeah the amount of dancing needed to get to the string interpolation setup is a no go. Still a fun mental exercise in the context (and FWIW, the problem is great at isolating in on different block behaviors as silly as it is on its own). Thanks!
1

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

6 Comments

The variables group_1, group_2, group_3 are givens in the question (check the link), so why not skip the creation of another variable and just write [group_1, group_2, group_3].map ...?
@CarySwoveland See the first sentence wherein he states that you don't need to have “a variable for each group”.
@coreyward, yes, but that changes the question, a no-no. Moreover, the solution should work with any value (array) for each of the three variables. This only works with three literal arrays. Yes, it's a poor question.
@CarySwoveland, the code OP already has is correct (codecademy says it is OK), so I suppose OP does not want a code to pass the codecademy challenge (because he already nailed it). OP just want to know some way to generalize the code because he is seeing a lot of repetition and similar things. The fact this code is from codecademy is irrelevant. Look at the last sentence in the question: "Is it possible, when objects hold repeatable patterns like these do, to use an Enumerable method in this way?"
Even better is to just declare all the groups in one shot: groups = [ [ ... ], [ ... ], .... ] to avoid the repeated push calls. Also since that Proc is only used once it might as well be inlined.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.