Как округлить одно значение в хэше? - PullRequest
0 голосов
/ 01 июня 2018

В контексте тяжелой атлетики я пытаюсь рассчитать количество тарелок, необходимых на каждой стороне штанги, с учетом общего веса, который нужно поднять, и предположим, что бар 45 фунтов.Самая маленькая тарелка весит 2,5 фунта, и я бы хотел округлить до ближайшего количества тарелок по 2,5 фунта, необходимых для каждой стороны.В настоящее время при общем весе в 140 фунтов результат выглядит следующим образом:

{:"45"=>1, :"2.5"=>0.8}

Как округлить до ближайшего целого числа (0 или 1) только значение для таблички '2.5'?

def plates_for(lb)
lb = (lb - 45) / 2
  plate_values = {'45': 45, '25': 25,'10': 10, '5': 5, '2.5': 2.5}
  pairs = plate_values.map do |plate, weight|
    number_of_plates = lb / weight
    lb = lb % weight
    [plate, number_of_plates]
  end

  plates_needed = pairs.select { |plate, weight| weight > 0 }
  p plates_needed.to_h
end

plates_for(140)

Ответы [ 2 ]

0 голосов
/ 01 июня 2018

Вот как я бы подошел:

def plates_for(lb)
  lb = (lb - 45).fdiv(2)
  plate_values = { '45': 45, '25': 25, '10': 10, '5': 5, '2.5': 2.5 }
  pairs = {}
  plate_values.each do |plate, weight|
    pairs[plate], lb = lb.divmod(weight)
  end
  pairs[:'2.5'] += 1 if lb > 0
  pairs.select { |_, count| count > 0 }
end

plates_for(140) #=> {:"45"=>1, :"2.5"=>1}

Заметные изменения:

  • Я использую fdiv для преобразования оставшихся lb до десятичного числа.
  • В цикле я вычисляю частное и остаток через divmod, который гарантирует, чточисло пластин - целое число.
  • После цикла я добавляю еще одну пластину 2.5, если остаток еще не равен нулю.
0 голосов
/ 01 июня 2018

Исходный ответ:

plates_needed[:'2.5'] = plates_needed[:'2.5'].round

По умолчанию это округляется до ближайшего целого числа и до , если оно находится на полпути между ними.Если вы хотите использовать другое поведение для округления до ближайшей половины, вы можете указать дополнительное ключевое слово:

2.5.round(half: :up)      #=> 3 (DEFAULT)
2.5.round(half: :down)    #=> 2
2.5.round(half: :even)    #=> 2
3.5.round(half: :up)      #=> 4 (DEFAULT)
3.5.round(half: :down)    #=> 3
3.5.round(half: :even)    #=> 4

В качестве альтернативы, если вы хотите _always_round down, тогда используйте Integer#floor;и если вы хотите всегда округлить, используйте Integer#ceil.

Полное решение:

def plates_for(lb)
  lb = (lb - 45).to_f / 2
  plate_values = [45, 25, 10, 5, 2.5]
  pairs = plate_values.map do |weight|
    number_of_plates = (lb / weight).round
    lb -= number_of_plates * weight
    [weight, number_of_plates]
  end.to_h

  pairs.select { |weight, number_of_plates| number_of_plates > 0 }
end

p plates_for(140) #=> {45=>1, 5=>1}

Я изменил несколько тонких частейвашего кода.Обратите внимание, что окончательный результат в моем коде отличается !Я получаю {45=>1, 5=>1}, что правильно.Изменения:

  • Добавлено to_f в строке 2. Без этого вы округляете необходимый вес на каждой стороне бара на 0.5, если общий требуемый вес был четным.Например, (140 - 45) / 2 == 47, но (140 - 45).to_f / 2 == 47.5.
  • Определите plate_values как простое Array, чтобы избежать путаницы.Не нужно было инициализировать это как Hash.
  • Добавить Integer#round к расчету количества пластин.Это предотвращает назначение нецелых значений.Как обсуждалось выше, есть варианты, которые вы можете использовать здесь.
  • Поскольку (lb / weight).round может не будет таким же, как lb % weight (то есть, если мы округлим!), Это будетнеправильно использовать это значение здесь.Всегда вычитайте величину веса, которую мы фактически добавили к бару.
  • Немедленно вызовите .to_h в результате этого сопоставления для упрощения.
  • Нет необходимости назначать другую переменную ниже, для упрощения.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...