在此 CashRegister 中查找产品的频率 class

Find product's frequency in this CashRegister class

我有 3 个简单的 类 CashRegister、Bill 和 Position。 CashRegister 由 Bill 对象组成,Bill 对象由 Position 对象组成。它们的实现方式如下

class CashRegister
  def initialize
    @bills = []
  end

  def product_frequency
    #???
  end

  def << bill
    @bills << bill
    self
  end
end

class Bill
  attr_reader :positions,:nr
  protected :positions

  def initialize(nr)
    @nr = nr
    @positions = []
  end

  def << pos
    @positions << pos
    self
  end
end

class Position
  attr_reader :product,:quantity,:price
  def initialize(product,quantity,single_price)
    @product = product
    @quantity = quantity
    @price = single_price * quantity
  end
end   

我想编写一个 product_frequency 方法来计算产品在 CashRegister 中的购买频率。此方法 returns 一个散列结果,以产品为键,以频率为值。 一个例子是:

pos1 = Position.new('Chicken',    5,      12)
pos2 = Position.new('Soup',       6,      24)
pos3 = Position.new('Burger',     3,      19)
pos4 = Position.new('Chicken',    2,      12)
pos5 = Position.new('Soup',       8,      24)
pos6 = Position.new('Burger',     9,      19)

bill1 = Bill.new(1) << pos1 << pos2 << pos3     #Chicken: 5;Soup: 6;Burger: 3
bill2 = Bill.new(2) << pos4 << pos3 << pos2     #Chicken: 2;Soup: 6;Burger: 3
bill3 = Bill.new(3) << pos6 << pos6 << pos6     #Chicken: 0;Soup: 0;Burger: 27
bill4 = Bill.new(4) << pos4 << pos5 << pos4     #Chicken: 4;Soup: 8;Burger: 0

my_cash_register = CashRegister.new << bill1 << bill2 << bill3 << bill4
my_cash_register.product_frequency    #{'Chicken' => 11, 'Soup' => 20, 'Burger' => 33}

我怎样才能达到那个结果?

如果您只是想统计每个产品被购买了多少次,那么这里是:

  def product_frequency
    product_frequency = {}
    @bills.each do |bill|
      bill.positionen.each do |position|
        @product_frequency[position.product] ||= 0
        @product_frequency[position.product] += position.quantity
      end
    end
    product_frequency
  end

这只是一种方法。代码很简单,所以我想你可以理解它是如何工作的

您可以为每个嵌套 class 定义 #frequency,然后递归地收集哈希值。

class Hash
  def additive_merge!(hash)
    hash.each { |k,v| self[k] ? self[k] += v : self[k] = v }
    self
  end
end

class CashRegister
  def initialize
    @bills = []
  end

  def product_frequency
   @bills.map(&:frequency).reduce(&:additive_merge!)
  end

  def << bill
   @bills << bill
   self
  end
end

class Bill
  attr_reader :positionen,:nr
  protected :positionen

  def initialize(nr)
    @nr = nr
    @positions = []
  end

  def << pos
   @positions << pos
   self
  end

  def frequency
    @positions.map(&:frequency).reduce(&:additive_merge!)
  end
end

class Position
  attr_reader :product,:quantity,:price

  def initialize(product,quantity,single_price)
    @product = product
    @quantity = quantity
    @price = single_price * quantity
  end

  def frequency
    { product => quantity }
  end
end

主要取自 Bartosz Bonisławski 的解决方案。但是由于 bill 中的 positionenprotected,我们首先必须通过在 Bill 中定义一个 each 函数来使其可访问,该函数接受一个块并应用它positions 中的每个 position。我们也为 CashRegister.

做同样的事情
class CashRegister
  def initialize
    @bills = []
  end

  def each(&block)
    @bills.each(&block)
  end

  def product_frequency
    result = {} 
    each { |bill| 
      bill.each { |position| 
        result[position.product] ||= 0 
        result[position.product] += position.quantity 
      } 
    } 
    result 
  end

  def << bill
    @bills << bill
    self
  end
end

class Bill
  attr_reader :positions,:nr
  protected :positions

  def initialize(nr)
    @nr = nr
    @positions = []
  end

  def each(&block)
    @positions.each(&block)
  end

  def << pos
    @positions << pos
    self
  end
end

class Position
  attr_reader :product,:quantity,:price
  def initialize(product,quantity,single_price)
    @product = product
    @quantity = quantity
    @price = single_price * quantity
  end
end