-1

I'm working on Felipe's Taqueria in Pset 3. Here is my code:

  # Set initial cost of order to $0
order = 0

# Put menu in dict
menu = {
    "Baja Taco": 4.25,
    "Burrito": 7.50,
    "Bowl": 8.50,
    "Nachos": 11.00,
    "Quesadilla": 8.50,
    "Super Burrito": 8.50,
    "Super Quesadilla": 9.50,
    "Taco": 3.00,
    "Tortilla Salad": 8.00
}

while True:

    try:
        # Get customer order
        item = input("Item: ")
        # Make sure order is title cased
        item = item.title()
        # Look up item order in menu dict
        for item in menu:
            item_cost = menu.get(item)
            break
        order = order + item_cost
        # Convert order total to two decimal places
        order = "%.2f" % order
        # Print order total
        print(f"Total: ${order}")
    # Check for key errors
    except KeyError:
        pass
    # End program when customer enters ctrl-d
    except EOFError:
        break

The code takes the first order input by the user just fine, but after that I keep getting this error:

Traceback (most recent call last):
  File "/workspaces/65269393/taqueria/taqueria.py", line 29, in <module>
    order = order + item_cost
            ~~~~~~^~~~~~~~~~~
TypeError: can only concatenate str (not "float") to str

Can anyone see where I am going wrong?

2 Answers 2

0

This item_cost = menu.get(item) will set item_cost to the entered item, a str type. Program needs to get the value (cost) for the entered key (item).

2
  • Thank you! I'll check that out
    – getsendy
    Commented Aug 13 at 20:59
  • I haven't said this I think ever, but I think you are missing the problem and bigger issues entirely. There is value shadowing, completely unneeded looping over a dictionary and other problems. item_cost=menu.get(item) has a different problem entirely than what you are providing, and I'm actually unclear on how its becoming a string and not a tuple with how it's currently written. Again I've never said this before Dino but this is an odd case that required me looking closer.
    – UpAndAdam
    Commented Aug 14 at 15:29
0

Problems

There's a bigger issue here. You are not using item properly, not using the dictionary menu properly, your loop is sabotaging you and you might be printing at the wrong time

  • You ask the user for item to be priced but you then ignore that value because you use a for loop where you iterate over the menu dictionary, overriding item with the loop variable. This is totally wrong and not needed.
    • Don't use a for loop to find an entry in a dictionary by its key. The entire point of using a dictionary is so you can do a fast search for the key at average time (O(logN)) without iteration (O(N)) at the slight cost of tree balancing upon insertion and deletion.
    • Even if you want to iterate this isn't how you do it efficiently, and you are not checking that the item you are 'get'ing from menu is actually the item that the user asked for because of your shadowing.
    • In fact because you use an iterating loop, every single time you are retrieving the first item in the menu dictionary (by its sorted order regardless of what the user enters) and breaking.
    • To understand I suggest you that you try inserting a print of item in the loop before the get to see what you are always retrieving.
    • Similarly try printing the value of item_cost after you retrieve it to see what you got
# your old code
item = input("Item: ")
item = item.title() 

# now get the price for the item.. if you want a KeyError for not found you can't use get..
# this will put the value of the dictionary entry with key `item` into item_cost.
# you could be more pedantic and cast it as a float or a double it you wanted.
# if item isn't a key in menu it will raise a KeyError
item_cost = menu[item]    

## alternative using get and a sentinel value
# this will return 0 if the item isn't found and you can then decide 
# what to do if item_cost is 0; or if 0 is an allowed price 
# perhaps -1 and -1 can be an indicator it wasn't found
item_cost = menu.get(item, 0) 


### contrast this with how you'd find it if it was a list of tuples

my_item = input("Item: ")
my_item = item.title
item_cost = 0
# assumes that `items` is a list of tuples of the form (name, value)
for item in items:
    if my_item == item[0]:
        item_cost = item[1]
        break
    pass

# note how in worst case this has to iterate and check every item in the list, however long the list is.


  • When are supposed to break from your loop and print the total?
    Right now you would be printing the the total every single time.
    Are you supposed to do that?
    Or are you only supposed to print the total after the EOFFile error is caught?

Key Takeaway

This problem is about learning the value of the dictionary data structure and how it is different from a list

Dictionary

  1. average fast lookup for keys, worst case O(n), average case is O(log(n)), basically binary search on tree depth
  2. iterable by key sorted order
  3. potentially slower time to insert or delete an item from the container (because it could cause the tree to be rebalanced which could be expensive and I believe is polynomial time (worse than linear)

List

  1. poor look up time for a given element (linear, O(n), directly follows the length of the list, because you have to start from one end and check every item and the items are not going to likely be cached for quick lookup
  2. iterable by insertion or manually manipulated order
  3. insertion and deletion of a given entry is super fast if you have a reference to its location (O(1), constant time), such as adding to beginning or end, or if you have the location for another reason. Otherwise removal / insertion from middle requires a search firsts and becomes O(n) to drop an item in the middle somewhere)

So when do you use each?

Dictionary

If you need to search through a number of items a lot and are not just working on the first or last item, and there is a unique key for the item, dictionary or unsorted dictionary are your friends.

You might spend a little longer building the container but if the bulk of the operations are lookups, the search time savings will pay off massively.

Additionally, if the bulk of your additions or removals are not at the front or back item but unknown locations in the middle this will be helpful.

A great example could also be if you constantly have to update entries for different keys. Like if each key was a product ID in your inventory and you had to track how many were in stock, or in different locations, as well as the price and other meta data. You aren't constantly adding or removing items from the inventory, though some may have a 'count' of zero, but occasionally new products are introduced or discontinued.

List

If you are constantly adding and removing items mostly from the front or back, and dont generally have to do a deep search for items in the middle, and searching isn't the priority or dominant activity, a list will be faster because you don't care about the slow search time that you wont be impacted by, you care about the quick insert/deletion/modification.

Great examples of this are very small datasets, or cases where the data is more like a queue or a stack where you are only concerned with say the order the items came in, and processing the 'next' order and removing it... and maybe occasionally you have to iterate through to cancel a request. Or other cases where you dont need to search and only care about the ordering of the items, and items come and go frequently. In these cases you want a list or a list-like structure.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .