6
\$\begingroup\$

How should I approach refactoring this code?

def separate_comma(number)
  a = number.to_s.split('')
  b = a.size/3.0
  if a.size < 4
    p number.to_s 
  elsif a.size%3 == 0
    n = -4
    (b.to_i-1).times do |i|
      a.insert(n, ',')
      n -= 4
    end
    p a.join("")
  else
      n = -4
    b.to_i.times do |i|
      a.insert(n, ',')
      n -= 4
    end
  p a.join("")
  end
end


separate_comma(97425)    # => "97,425"
separate_comma(89552600) # => "895,926,600"
separate_comma(0)       # => "0"
separate_comma(100)     # => "100"
\$\endgroup\$
  • 2
    \$\begingroup\$ Just a hint: Remember i18n. Among other things the symbol for grouping digits isn't always a comma, so avoid hard-coding it. \$\endgroup\$ – rjnilsson Jul 4 '13 at 8:08
9
\$\begingroup\$

I am not sure how hard may be for a newbie to take on functional programming, but if you are interested in new ways of programming, check it out. A more specific article on Ruby: FP with Ruby. If you think in terms of expressions (what things are) instead of statements (update, insert, delete, ...), code is more declarative (and usually shorter). I'll use no regexps to show an alternative approach to the existing answer:

def separate_comma(number)
  number.to_s.chars.to_a.reverse.each_slice(3).map(&:join).join(",").reverse
end

If you want to support decimals:

def separate_comma(number)
  whole, decimal = number.to_s.split(".")
  whole_with_commas = whole.chars.to_a.reverse.each_slice(3).map(&:join).join(",").reverse
  [whole_with_commas, decimal].compact.join(".")
end
\$\endgroup\$
6
\$\begingroup\$

This does the same thing more succinctly

number.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse

source: https://stackoverflow.com/a/11466770/1429887

It converts the number to a string, reverses it, places a comma every three digits (if it is followed by a digit), then reverses it back to its original order.

You might want to make it a function such as

def format_number(number)
  number.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse
end

so that you can call the process multiple times

However, this method does not work with numbers that contain 3+ decimals. To solve that:

def format_number(number)
  number = number.to_s.split('.')
  number[0].reverse!.gsub!(/(\d{3})(?=\d)/, '\\1,').reverse!
  number.join('.')
end

This method splits the integer into the whole number part and the decimal part. It then adds the comma to the whole number and then tacks on the second decimal part.

[edit]: the second line of that function should have been number[0] to get the first element (the whole number one). Sorry if you viewed it before I realized my mistake.

\$\endgroup\$
0
\$\begingroup\$

If you're using Ruby on Rails, there is a number helper for doing just that.

number_with_delimiter(12345,delimiter: ",")   # => 12,345
\$\endgroup\$
  • 5
    \$\begingroup\$ That function is part of ActionView. The question does not mention that Ruby on Rails is being used. \$\endgroup\$ – 200_success Sep 14 '18 at 0:22
  • \$\begingroup\$ Good point.. that was an assumption. \$\endgroup\$ – mikey9 Sep 14 '18 at 21:31

protected by Jamal Sep 15 '18 at 5:39

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.