Search code examples
ruby

Ruby - How to calculate subtotal of items in a grocery list


I want to create a program where a user basically "creates" a grocery list where the user inputs item and price until they want to quit. If the user enters ’q’ or ’Q’, then the program should stop prompting the user and instead should calculate the subtotal, add in a nominal 6% sales tax, and display the total result.

I got the first part down where user inputs their item and price but I don't know how to make it tell me the subtotal and give them a receipt. I have been trying for 7 hours!! When I run it, it's supposed to say:

Enter an item and its price, or ’Q/q’ to quit: eggs 2.13
Enter an item and its price, or ’Q/q’ to quit: milk 1.26
Enter an item and its price, or ’Q/q’ to quit: batteries 3.14
Enter an item and its price, or ’Q/q’ to quit: q
Receipt:
--------
eggs => $2.13
milk => $1.26
batteries => $3.14
---------
subtotal: $6.53
tax: $0.39
total: $6.92

Here is the code I made: (Can anyone please help me???)

def create_list
puts 'Please enter item and its price or type "quit" to exit'
items = gets.chomp.split(' ')
grocery_list  = {}
index = 0 
until index == items.length
grocery_list[items[index]] = 1 
index += 1
end
grocery_list
end

def add_item (list)
items  = ''
until items == 'quit'
puts "Enter a new item & amount, or type 'quit'."
items = gets.chomp
if items != 'quit'
  new_item = items.split(' ')
  if new_item.length > 2
    #store int, delete, combine array, set to list w/ stored int
    qty = new_item[-1]
    new_item.delete_at(-1)
    new_item.join(' ')
    p new_item
  end
  list[new_item[0]]  = new_item[-1]
else
  break
end
end
list
end

 add_item(create_list)

 puts "Receipt: "
 puts "------------" 

Solution

  • Not sure you need hashes for this as they are used to store key value pairs. Also you should organize your code where you define your variables, then your methods, then run your code last. Keep the methods simple.

    #define instance variabes so they can be called inside methods
    @grocery_list = [] # use array for simple grouping. hash not needed here
    @quit = false # use boolean values to trigger when to stop things.
    @done_shopping = false
    @line = "------------" # defined to not repeat ourselves (DRY)
    
    #define methods using single responsibility principle.
    def add_item
      puts 'Please enter item and its price or type "quit" to exit'
      item = gets.chomp
      if  item == 'quit'
        @done_shopping = true
      else
        @grocery_list << item.split(' ')
      end
    end
    
    # to always use 2 decimal places
    def format_number(float)
      '%.2f' % float.round(2)
    end
    
    #just loop until we're done shopping.
    until @done_shopping
      add_item
    end
    
    puts "\n"
    #print receipt header
    puts "Receipt: "
    puts @line
    
    #now loop over the list to output the items in arrray.
    @grocery_list.each do |item|
      puts "#{item[0]} => $#{item[1]}"
    end
    
    puts @line
    # do the math
    @subtotal = @grocery_list.map{|i| i[1].to_f}.inject(&:+) #.to_f converts to float
    @tax = @subtotal * 0.825
    @total = @subtotal + @tax
    
    #print the totals
    puts "subtotal: $#{format_number @subtotal}"
    puts "tax: $#{format_number @tax}"
    puts "total: $#{format_number @total}"
    #close receipt
    puts @line