2013-12-17 6 views
1

Я пытаюсь создать очень простую корзину для покупок Ruby, и мне нужно дать скидки, если пользователь покупает определенные комбинации товаров. Они указаны в @costs - если объем является истинным, пользователь получает скидку (из: bulk_price) для покупки: bulk_num товаров. У меня есть основные обвинения, но теперь мне нужно вычитать скидки в определенных случаях. Вот то, что я до сих пор:Как предоставить скидки в простой корзине Ruby?

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 

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

+0

Его не ясно, что ваш вопрос. – Zach

+0

Я не могу понять, как фактор скидки. Некоторые предметы дисконтируются - например, A составляет 1 доллар США, если вы покупаете 4 из них, но B никогда не дисконтируется. – USK

+0

Я уверен, что эта тема будет закрыта, потому что у вас нет другого вопроса, кроме «не могли бы вы помочь мне исправить мой код?», Но мне кажется, что предметы должны иметь свойство «скидка». Когда вы вычисляете общее количество, вы проверяете, есть ли у товара скидка, а затем примените его. – Zach

ответ

2

Несколько вещей:

  • Отступ ваш код правильно, он будет делать это намного проще для вас в долгосрочной перспективе.
  • Удалить :total от attr_accessor, он не требуется, и сгенерированный метод total будет переопределен тем, который вы определяете позже.
  • Рассмотрите возможность создания каждого предмета, который знает свою стоимость, а не поиск стоимости каждого товара в @costs. Концептуально, не имеет смысла для «корзины покупок» отслеживать все цены на все предметы в вашем магазине.
  • Сделайте свой total метод функциональным. Не беспокойтесь, вычитая из @subtotal - это вызовет проблемы, если total вызывается более одного раза.
  • На самом деле, subtotal также будет лучше, если вы пересчитывать каждый раз, когда необходимо:

    def subtotal 
        @item_array.reduce(0) { |sum,item| sum + (@costs[item][:price] || 0) } 
    end 
    

Это не может быть очевидным для вас сейчас, но писать код «функционально», как это делает его легче чтобы избежать ошибок. Вы можете кэшировать значения, если они действительно дороги для вычисления, и будут необходимы не один раз, но в этом случае нет необходимости.

  • Для total, вы можете сделать что-то вроде:

    def total 
        result = self.subtotal 
        # check which discounts apply and subtract from 'result' 
        result 
    end 
    
+0

Спасибо! Извините, я супер новичок в таких задачах. ОК. Попытка реализовать часть этого, чтобы убедиться, что я понимаю – USK

+0

Большинство потрясающих функциональных методов программирования Ruby поступают из модуля [Enumerable] (http://ruby-doc.org/core-2.0.0/Enumerable.html). Обязательно ознакомьтесь с документацией, если вы изучаете такие методы, как каждая, карта, сокращение и find_all. Также обратите внимание, что классы String, Array, Hash и другие обычные классы Ruby включают методы Enumerable. –

1

Поскольку ваш вопрос включает в себя упражнения, я решил изменить его вокруг немного, чтобы сделать некоторые моменты, которые вы могли бы оказаться полезными , Несколько замечаний:

  • я переименовал scan в checkout, чтобы бывший спутать с String#scan
  • величина, порядок задается для каждого элемента упорядочены, в виде хэша, который передается методу checkout;
  • Я изменил :bulk_price на цену единицы товара, которая применяется, если :bulk истинно и количество заказано не менее :bulk_num.
  • Я изменил @costs на хэш, потому что вам нужно получить доступ к именам элементов, которые теперь являются ключами.
  • Я переехал @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 
Смежные вопросы