0

I am doing some exercises to help with understanding how various enumerables work under the hood. To do so I have to solve a problem using .each then solve the same problem with the enum that I'm working on, in this case .sort_by. I have everything figured out with the exception of how to actually compare the cents aka the decimal places in these float numbers.

In my code transformed will be an array of arrays. Each array inside transformed will consist of the actual data being compared along with the price that data came from. Because this is an each iteration, I cannot hardcode the data to compare. Because it's a float instead and not a string or array, I cannot tell my code to compare price[-2..-1] as I might with a string/array. I can't multiply each price by 100 and compare those because that would compare the entire amount, not just the cents as required.

  def test_sort_by_number_of_cents
    prices = [3.02, 9.91, 7.9, 10.01, 11.0]
    transformed = []
    prices.each do |price|
      transformed << [X, price]
    end
    transformed = transformed.sort 
    sorted = []
    transformed.each do |sort_key, price|
      sorted << price 
    end 
    assert_equal [11.0, 10.01, 3.02, 7.9, 9.91], sorted
  end

The expected result can be seen in the assertion: [11.0, 10.01, 3.02, 7.9, 9.91]

  • So, the question can be distilled down to "how to get the fractional part of a float"? – Sergio Tulentsev Jul 24 '19 at 21:20
  • " I cannot tell my code to compare price[-2..-1]" - you actually can. Just convert it into a string. :) – Sergio Tulentsev Jul 24 '19 at 21:21
  • A few options are listed here: https://stackoverflow.com/questions/12406032/get-fraction-part-of-a-decimal-number – Sergio Tulentsev Jul 24 '19 at 21:23
  • That did give me some progress - by comparing as a string[-2..-1] my output is: [11.0, 7.9, 10.01, 3.02, 9.91] . Thank you! – StarPerfect Jul 24 '19 at 21:30
  • 1
    Just a pro-tip since you're learning. Don't ever do financial calculations with floats. Floating point operations are not precise and can lead to major errors. Instead represent monetary values as whole numbers and insert the decimal point before displaying :) – watzon Jul 24 '19 at 21:59
  • I'm confused, why can't you just do a `>` / `<` (greater/less than) comparison? – max pleaner Jul 24 '19 at 22:01
  • Do you want something like the following: `price = 23.67; dollars = price.to_i #=> 23; cents = (100 * (price - dollars)).round #=> 67`? When working with currency you should be using [BigDecimal](https://ruby-doc.org/stdlib-2.6.3/libdoc/bigdecimal/rdoc/BigDecimal.html) to avoid problems with round-off errors. – Cary Swoveland Jul 24 '19 at 22:02
  • @maxpleaner: apparently, they want to sort only by fractional part. For whatever reasons. – Sergio Tulentsev Jul 25 '19 at 09:00

1 Answers1

0

My answer:

prices = [3.02, 9.91, 7.9, 10.01, 11.0]
result = prices.sort_by do |price|
  price.modulo(1)
end
p result

Or:

prices = [3.02, 9.91, 7.9, 10.01, 11.0]
result = prices.sort_by do |price|
  price - price.to_i
end
p result
ouflak
  • 2,458
  • 10
  • 44
  • 49
  • Please consider including a brief explanation of [how and why this solves the problem](https://meta.stackoverflow.com/q/392712/13138364). This will help readers to better understand your solution. – tdy Nov 01 '21 at 22:11