Применение различных множителей к целому числу в зависимости от порога - PullRequest
2 голосов
/ 01 февраля 2020

Мне нужно построить программу, которая рассчитывает ежегодную стоимость минут, используемых для телефонных операторов, и она зависит от разных тарифов.

Например, у одного телефонного оператора могут быть следующие тарифы:

  "rates":           [
      {"price": 15.5, "threshold": 150},
      {"price": 12.3, "threshold": 100},
      {"price": 8}
    ],

у операторов может быть несколько тарифов, при этом последний тариф всегда не имеет порога.

, поэтому в Например, первые 150 минут будут оплачиваться по 15,5 пенсов в минуту, следующие 100 минут будут оплачиваться по 12,3 пенсов в минуту, а все последующие минуты будут оплачиваться по 8 пенсов.

Поэтому, если:

AnnualUsage = 1000

общая стоимость составила бы 95,55.

Я изо всех сил пытаюсь представить метод, который бы учитывал различные тарифы, которые мог бы иметь оператор, и умножал значение на другую цену в зависимости от порога.

Пожалуйста, помогите!

Ответы [ 4 ]

3 голосов
/ 01 февраля 2020

Просто еще один вариант, я думаю, это само за себя:

rates =  [
      {price: 15.5, threshold: 150},
      {price: 12.3, threshold: 100},
      {price: 8}
    ]

annual_usage = 1000

res = rates.each_with_object([]) do |h, ary|
  if h.has_key?(:threshold) && annual_usage > h[:threshold]
    annual_usage -= h[:threshold]
    ary << h[:threshold] * h[:price]/100
  else
    ary << annual_usage * h[:price]/100
  end
end

res #=> [23.25, 12.3, 60]
res.sum #=> 95.55

Взгляните на Enumerable # each_with_object .

2 голосов
/ 02 февраля 2020
def tot_cost(rate_tbl, minutes)
  rate_tbl.reduce(0) do |tot,h|
    mins = [minutes, h[:threshold] || Float::INFINITY].min
    minutes -= mins
    tot + h[:price] * mins
  end
end

rate_tbl = [
  { price: 15.5, threshold: 150},
  { price: 12.3, threshold: 100 },
  { price: 8 }
]

tot_cost(rate_tbl, 130) #=> 2015.0 (130*15.5)
tot_cost(rate_tbl, 225) #=> 3247.5 (150*15.5 + (225-150)*12.3)
tot_cost(rate_tbl, 300) #=> 3955.0 (150*15.5 + 100*12.3 + (300-250)*8)

При желании h[:threshold] || Float::INFINITY можно заменить на

h.fetch(:threshold, Float::INFINITY)
1 голос
/ 02 февраля 2020

С объектно-ориентированным подходом вы можете удалить явные операторы if ..else и, возможно, сделать код более понятным.

class Total
  attr_reader :price

  def initialize(usage)
    @usage = usage
    @billed_usage = 0
    @price = 0
  end

  def apply(rate)
    applicable_usage = [@usage - @billed_usage, 0].max
    usage_to_apply = [applicable_usage, rate.fetch(:threshold, applicable_usage)].min

    @price += usage_to_apply * rate[:price]
    @billed_usage += usage_to_apply
  end
end

Простое использование с each методом

rates =  [
  {:price =>  15.5, :threshold => 150},
  {:price => 12.3, :threshold => 100},
  {:price => 8}
]

total = Total.new(1000)
rates.each { |rate| total.apply(rate) }

puts "Total: #{total.price}" # Total: 9555.0 (95.55)
1 голос
/ 01 февраля 2020
RATES = [
  {price: 15.5, threshold: 150},
  {price: 12.3, threshold: 100},
  {price: 8}
]

def total_cost(annual_usage)
  rate_idx = 0
  idx_in_threshold = 1

  1.upto(annual_usage).reduce(0) do |memo, i|
    threshold = RATES[rate_idx][:threshold]
    if threshold && (idx_in_threshold > RATES[rate_idx][:threshold])
      idx_in_threshold = 1
      rate_idx += 1
    end
    idx_in_threshold += 1
    memo + RATES[rate_idx][:price]
  end
end

puts total_cost(1000).to_i
# => 9555

Ключевые понятия:

  • с использованием перечислимого метода, такого как , уменьшение для постепенного построения решения. В качестве альтернативы вы можете использовать each, но reduce - это идиоматизм c.
  • отслеживание прогресса в списке тарифов с помощью переменных rate_idx и idx_in_threshold. Они дают вам всю информацию, необходимую для определения того, следует ли переходить на следующий уровень.

Кроме того, не пишите такие ключи ha sh, как "price": 15.5 - просто удалите цитаты, это более идиоматично c.

...