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
- average fast lookup for keys, worst case O(n), average case is O(log(n)), basically binary search on tree depth
- iterable by key sorted order
- 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
- 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
- iterable by insertion or manually manipulated order
- 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.