0

The integer variables are:

toonie = 2, loonie = 1, quarter = 1, dime = 0, nickel = 1, penny = 3

I want the final output to be

"2 toonies, 1 loonie, 1 quarter, 1 nickel, 3 pennies"

Is there a way to interpolate this all from Ruby code inside [] array brackets and then add .join(", ")?

Or will I have to declare an empty array first, and then write some Ruby code to add to the array if the integer variable is greater than 0?

2
  • 3
    Why do you have single variables in the first place, is it an option to store the values in a hash? Commented Feb 12, 2016 at 17:07
  • @spickermann You're right. It must be Friday, or I'm a newbie. I'm going to go with both, and also use a hash instead as others suggested in their answers. Commented Feb 12, 2016 at 17:18

4 Answers 4

2

I would do something like this:

coins = { toonie: 2, loonie: 1, quarter: 1, dime: 0, nickel: 1, penny: 3 }
coins.map { |k, v| pluralize(v, k) if v > 0 }.compact.join(', ')
#=> "2 toonie, 1 loonie, 1 quarter, 1 nickel, 3 penny"

Note that pluralize is a ActionView::Helpers::TextHelper method. Therefore it is only available in views and helpers.

When you want to use your example outside of views, you might want to use pluralize from ActiveSupport instead - what makes the solution slightly longer:

coins.map { |k, v| "#{v} #{v == 1 ? k : k.pluralize}" if v > 0 }.compact.join(', ')
#=> "2 toonie, 1 loonie, 1 quarter, 1 nickel, 3 penny"
Sign up to request clarification or add additional context in comments.

3 Comments

It's worth noting that there's a pluralize method takes arguments that do the == 1 comparison for you: pluralize(coins[:quarter], 'quarter').
@tadman: There are two different versions of the pluralize method. The one from ActionView does, the one from ActiveSupport doesn't. I used both versions in my answer, please note the difference between both examples.
Right! I didn't see the first one since it's buried in a pretty gnarly one-liner, but there it is. Worth explaining there's actually two different methods that are similar in output, yet one's part of String and the other isn't.
1

Can be done in rails:

hash = {
  "toonie" => 2,
  "loonie" => 1,
  "quarter" => 1,
  "dime" => 0,
  "nickel" => 1,
  "penny" => 3
}

hash.to_a.map { |ele| "#{ele.last} #{ele.last> 1 ? ele.first.pluralize : ele.first}" }.join(", ")

Basically what you do is convert the hash to an array, which will look like this:

[["toonie", 2], ["loonie", 1], ["quarter", 1], ["dime", 0], ["nickel", 1], ["penny", 3]]

Then you map each element to the function provided, which takes the inner array, takes the numeric value in the last entry, places it in a string and then adds the plural or singular value based on the numeric value you just checked. And finally merge it all together

=> "2 toonies, 1 loonie, 1 quarter, 1 nickel, 3 pennies"

Comments

1

I'm not sure what exactly you're looking for, but I would start with a hash like:

coins = {"toonie" => 2, "loonie" => 1, "quarter" => 1, "dime" => 0, "nickel" => 1, "penny" => 3}

then you can use this to print the counts

def coin_counts(coins)
  (coins.keys.select { |coin| coins[coin] > 0}.map {|coin| coins[coin].to_s + " " + coin}).join(", ")
end

If you would like appropriate pluralizing, you can do the following:

include ActionView::Helpers::TextHelper
def coin_counts(coins)
  (coins.keys.select { |coin| coins[coin] > 0}.map {|coin| pluralize(coins[coin], coin)}).join(", ")
end

Comments

0

This is just for fun and should not be used in production but you can achieve it like

def run
  toonie = 2
  loonie = 1
  quarter = 1
  dime = 0
  nickel = 1
  penny = 3

  Kernel::local_variables.each_with_object([]) { |var, array|
   next if eval(var.to_s).to_i.zero?
   array << "#{eval(var.to_s)} #{var}"
  }.join(', ')
end

run # returns "2 toonie, 1 loonie, 1 quarter, 1 nickel, 3 penny"

The above does not implement the pluralization requirement because it really depends if you will have irregular plural nouns or whatever. I would go with a hash solution as described in the other answers

5 Comments

I'm feeling more than a little mortified you'd put eval in an example for beginners. This is the nuclear weapons approach. Every other answer uses a Hash, because that's the best plan here.
@tadman: especially since we have Binding#local_variable_get for exactly this use case.
local_variable_get is also super smelly in production code. They're a big clue that you need to rethink your implementation.
at what point did I say that it should be used in production? Showing the language's capabilities, albeit a bad one in the case, shouldn't be considered a nuclear disaster. Not only I suggested for it to NOT be used in production but I also recommended a hash approach from one of the other answers
@JörgWMittag didn't know about Binding#local_variable_get! Thanks

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.