如何在简单的Ruby购物车中提供折扣?
我正在尝试制作一个非常简单的Ruby购物车,如果用户购买某些商品组合,我需要能够提供折扣。这些在@costs中表示-如果bulk为true,则用户购买:bulk\u num商品可获得折扣(即:bulk\u price)。我已经让它做了基本的收费,但现在我需要在某些情况下减去折扣。以下是我目前掌握的情况:如何在简单的Ruby购物车中提供折扣?,ruby,Ruby,我正在尝试制作一个非常简单的Ruby购物车,如果用户购买某些商品组合,我需要能够提供折扣。这些在@costs中表示-如果bulk为true,则用户购买:bulk\u num商品可获得折扣(即:bulk\u price)。我已经让它做了基本的收费,但现在我需要在某些情况下减去折扣。以下是我目前掌握的情况: class Cart attr_accessor :total, :costs, :item_array, :subtotal def initialize
class Cart
attr_accessor :total, :costs, :item_array, :subtotal
def initialize
@item_array=[]
@subtotal=0
@costs= [{"A"=>{:price=>2, :bulk=>true, :bulk_num=>4, :bulk_price=>7}}, {"B"=>{:price=>12, :bulk=> false}},{"C"=>{:price=>1.25,:bulk=>true, :bulk_num=>6, :bulk_price=>6}}, {"D"=>{:price=>0.15, :bulk=>false}}]
end
def scan(*items)
items.each do |item|
@item_array<<item
@costs.each do |cost|
if cost.has_key?(item)
@subtotal+=cost[item][:price]
end
end
@subtotal
end
end
def total
end
end
class购物车
属性存取器:总计,:成本,:项目数组,:小计
def初始化
@项_数组=[]
@小计=0
@成本=[{“A”=>{:价格=>2,:批量=>true,:批量数量=>4,:批量价格=>7},{“B”=>{:价格=>12,:批量=>false},{“C”=>{:价格=>1.25,:批量=>true,:批量数量=>6,:批量价格=>6},{“D”=>{:价格=>0.15,:批量=>false}]
结束
def扫描(*项)
项目。每个do |项目|
@item_数组有几件事:
- 适当地缩进代码,从长远来看,这将使代码更容易
- 从
attr\u访问器
中删除:total
,不需要它,生成的total
方法将被稍后定义的方法覆盖
- 考虑使每个项目成为一个了解其自身成本的对象,而不是在
@costs
中查找每个项目的成本。从概念上讲,“购物车”跟踪商店中所有商品的所有价格是没有意义的
- 使您的
总计方法发挥作用。不要费心从@subtotal
中减法——如果多次调用total
,将导致问题
- 实际上,如果您在需要时重新计算,
小计也会更好:
def subtotal
@item_array.reduce(0) { |sum,item| sum + (@costs[item][:price] || 0) }
end
现在您可能不太清楚,但是像这样“按功能”编写代码可以更容易地避免bug。如果值的计算非常昂贵,并且需要多次,则可以缓存这些值,但在这种情况下,不需要缓存
- 对于
total
,您可以执行以下操作:
def total
result = self.subtotal
# check which discounts apply and subtract from 'result'
result
end
由于你的问题涉及到一个练习,我决定将其稍作改动,提出一些你可能会觉得有用的观点。请注意:
- 我将
scan
重命名为checkout
,以免将前者与
- 以散列的形式为订购的每个项目提供订购数量,散列传递给
checkout
方法李>
- 我将
:bulk\u price
更改为适用于:bulk
为真且订购数量至少为:bulk\u num
的单价
- 我将
@costs
更改为散列,因为您需要访问项目名称,这些名称现在是键
- 出于两个原因,我把
@costs
搬到了课外。首先,数据可能会改变,所以在类定义中不应该硬连接数据。其次,如果希望不同的类实例使用不同的@成本
,这样做可以提供灵活性。您将看到,在创建新类实例时,我选择将该散列作为参数传递
- 我删除了你所有的访问者
- 如果您在
@costs
中输入的项目名称不是关键字,则会引发异常
这就是我采取的方法:
class Cart
def initialize(costs)
@costs= costs
end
def checkout(items)
purchases = {}
items.each do |(item, qty)|
cost = @costs[item]
raise ArgumentError, "Item '#{item}' not in @costs array" \
if cost == nil
if cost[:bulk] && qty >= cost[:bulk_num]
tot_cost = qty.to_f * cost[:bulk_price]
discount = qty.to_f * (cost[:price] - cost[:bulk_price])
else
tot_cost = qty.to_f * cost[:price]
discount = 0.0
end
purchases[item] = {qty: qty, tot_cost: tot_cost, discount: discount}
end
purchases
end
def tot_cost(purchases)
purchases.values.reduce(0) {|tot, h| tot + h[:tot_cost]}
end
def tot_discount(purchases)
purchases.values.reduce(0) {|tot, h| tot + h[:discount]}
end
end
costs = {"A"=>{price: 2, bulk: true, bulk_num: 4, bulk_price: 1.75},
"B"=>{price: 12, bulk: false },
"C"=>{price: 1.25, bulk: true, bulk_num: 6, bulk_price: 1.00},
"D"=>{price: 0.15, bulk: false }}
cart = Cart.new(costs)
purchases = cart.checkout({"A"=>6, "B"=>7, "C"=>4}) # item => quantity purchased
p purchases # => {"A"=>{:qty=>6, :tot_cost=>10.5, :discount=>1.5},
# => "B"=>{:qty=>7, :tot_cost=>84.0, :discount=>0.0},
# => "C"=>{:qty=>4, :tot_cost=>5.0, :discount=>0.0}}
p cart.tot_cost(purchases) # => 99.5
p cart.tot_discount(purchases) # => 1.5
不清楚你的问题是什么。我不知道如何考虑折扣。某些项目是打折的-例如,如果你买了4个项目,A可以享受1美元的折扣,但是B从来没有打折。我确信这个线程将关闭,因为你似乎没有什么问题,除了“你能帮我修复我的代码吗?”,但在我看来,项目应该具有“折扣”属性。当你计算总数时,你会检查一件物品是否有折扣,然后应用它。谢谢!对不起,像这样的任务我是个新手。好啊我将尝试实现其中的一些功能,以确保我了解Ruby的大多数很棒的函数式编程方法都来自该模块。在学习诸如each、map、reduce和find_all等方法时,一定要查看相关文档。另外,请注意,String、Array、Hash和其他常见Ruby类包括Enumerable的方法。