我有3个简单的类收银机,账单和职位。收银机由账单对象组成,账单对象由头寸对象组成。它们的实现方式如下
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方法,用于计算在收银机中购买产品的频率。此方法返回哈希作为结果,乘积作为键,频率作为值。一个例子是:
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}
我怎样才能实现这个结果?
主要取自Bartosz Bonisławski的解决方案。但是由于bill
中的positionen
是protected
的,我们首先必须通过在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
如果您只想计算每种产品的购买次数,那么这里是:
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
这只是一种方法。代码非常简单,所以我认为你可以弄清楚它是如何工作的
你可以为每个嵌套类定义#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