如何计算红宝石中总哈希值的百分比

时间:2019-08-14 23:13:45

标签: ruby

我有一个静态的json文件,其中包含:

{
  "homes": {
    "person_a": "windows+tables",
    "person_b": "lights+tables",
    "person_c": "doors+curtains"
 }
}

对于每个请求,应用程序都应计算3家保险公司的报价。业务需求如下:

如果匹配2个封面,则报价为费率的10%;如果仅匹配1个封面且报价为最大,则报价为20%;如果是第二个封面,则为25%;如果是第三个封面,则为30%。 / p>

来自用户的请求如下

{:curtains=>20, :tables=>30, :windows=>50}

如果该值为零(0),则系统不应返回引号

然后,应用程序将计算以下报价:

person_a: 8 (10% of 80 (two matches on windows and tables))
person_b: 7.5 (25% of 30 (one match on contents, the 2nd biggest cover))
insurer_c: 6 (30% of 20 (one match on curtains, the 3rd biggest cover)

这是我的解决方案:


require_relative './rules'

module Coverage
  class CalculateQuotes
    def initialize(quotes)
      @quotes = quotes
    end

    def get_rates
      result = []
      @insurer = Coverage::Rules.parse_file ## which will give {
                                        #"insurer_rates": {
                                       #"person_a": "windows+tables",
                                       # "person_b": "lights+tables",
                                       #"person_c": "doors+curtains"
                                      # }}
      @insurer[:insurer_rates].each do |k, v|
        @match_covers = match_cover(v.split("+"))
        result << [k, calculate_rate ]
      end
    end

    def match_cover(covers)
      covers = covers.map { |x| x.to_sym }
      @quotes.select { |k,v| covers.include?(k) }
    end

    def calculate_rate
      premium    = 0.0
      persentage = get_percentage_by_match_covers
      @match_covers.values.each do |v|
        premium += v * persentage
      end
      premium == 0 ? nil : premium
    end

    def get_percentage_by_match_covers
      if @match_covers.size == 2
        0.1
      elsif @match_covers.size == 1
        only_1_match_covers
      else
        0
      end
    end

    def only_1_match_covers
      index = position_of_customer_request
      case index
      when 0
        0.2
      when 1
        0.25
      when 2
        0.3
      else
        raise StandardError
      end
    end

    def position_of_customer_request
      (@quotes.to_a.reverse).index(@match_covers.to_a.flatten)
    end
  end
end


request = {:windows=>50, :contents=>30, :engine=>20}

Coverage::CalculateQuotes.new(request).get_rates

请帮助我了解如何使用SOLID红宝石原理更好地进行计算和编码?

1 个答案:

答案 0 :(得分:1)

数据

double_quote_rate = 0.1
single_quote_rate = [0.3, 0.25, 0.2]
request = {:curtains=>20, :tables=>30, :windows=>50}

代码

关键是创建一个将产品集映射到其计算值的哈希。

第一步是创建键值对,其中键是包含单个产品的集合:

require 'set'

h = single_quote_rate.zip(request.sort_by(&:last)).
      each_with_object({}) { |(rate, (product, score)),h|
        h[[product].to_set] = rate*score }
  #=> {#<Set: {:curtains}>=>6.0, #<Set: {:tables}>=>7.5,
  #    #<Set: {:windows}>=>10.0} 

请注意,single_quote_rate中的值按从大到小的顺序排列。中间计算如下:

single_quote_rate.zip(request.sort_by(&:last))
  #=> [[0.3, [:curtains, 20]], [0.25, [:tables, 30]],
  #    [0.2, [:windows, 50]]] 

现在添加两种产品的所有组合:

request.to_a.combination(2).each { |(product1, score1),(product2,score2)|
  h[[product1,product2].to_set] = double_quote_rate*(score1+score2) }

h #=> {#<Set: {:curtains}>=>6.0,
  #    #<Set: {:tables}>=>7.5,
  #    #<Set: {:windows}>=>10.0,
  #    #<Set: {:curtains, :tables}>=>5.0,
  #    #<Set: {:curtains, :windows}>=>7.0,
  #    #<Set: {:tables, :windows}>=>8.0} 

第一个计算如下:

enum = request.to_a.combination(2)
  #=> #<Enumerator: [[:curtains, 20], [:tables, 30],
  #                  [:windows, 50]]:combination(2)> 

我们可以将此枚举器转换为数组,以查看将传递给该块的三个元素(数组)。

enum.to_a
  #=> [[[:curtains, 20], [:tables, 30]],
  #    [[:curtains, 20], [:windows, 50]],
  #    [[:tables, 30], [:windows, 50]]] 

块变量分配如下:

(product1, score1),(product2,score2) = enum.next
  #=> [[:curtains, 20], [:tables, 30]] 
product1
  #=> :curtains 
score1
  #=> 20 
product2
  #=> :tables 
score2
  #=> 30 

将数组分解成其组成元素称为array decompostion

为方便起见,将request的键分配给变量:

keys = request.keys
  #=> [:curtains, :tables, :windows]

示例

hash = { "homes": { "person_a": "windows+tables",
                    "person_b": "lights+tables",
                    "person_c": "doors+curtains" } }

hash[:"homes"].transform_values do |s|
  h[s.split('+').map(&:to_sym).select { |s| keys.include?(s) }.to_set]
end
  #=> {:person_a=>8.0, :person_b=>7.5, :person_c=>6.0}

用于获得h的期望值的密钥的示例计算如下:

s = "lights+tables"
a = s.split('+')
  #=> ["lights", "tables"] 
b = a.map(&:to_sym)
  #=> [:lights, :tables] 
c = b.select { |s| keys.include?(s) }
  #=> [:tables] 
d = c.to_set
  #=> #<Set: {:tables}> 
h[d]
  #=> 7.5