Calling methods and iterating over list - python

I'm trying to ask for ingredients in a recipe via the input function. I want to store that ingredient in a dictionary, separated by quantity and ingredient. For example, an input of '3 eggs', should yield {'3': 'eggs'}.
The way i do this is with the separate() and convert_to_dict() methods.
I want to ask continuously for the ingredients by means of the input, hence the while True loop.
Basically, i do this via the following code:
ingredients_list = []
def separate(list):
for i in list:
return re.findall(r'[A-Za-z]+|\d+', i)
def convert_to_dict(list):
i = iter(list)
dct = dict(zip(i, i))
return dct
while True:
ingredient = input("Please input your ingredient: ")
ingredients_list.append(ingredient)
print(convert_to_dict(separate(ingredients_list)))
This works fine, but the only problem with it is that when i input another ingredient, the separate() and convert_to_dict() methods only seem to work for the first ingredient in the ingredient list. For example, i firstly input '3 eggs', and then '100 gr of flour', yet it only returns {'3': 'eggs'}. I'm sure there is something i'm missing, but can't figure out where it goes wrong.

I think you've got the idea of your key-value pairs the wrong way around!
Keys are unique. Updating a dictionary with an existing key will just override your value. So if you have 3 eggs, and 3 cups of sugar, how do you envision your data structure capturing this information?
Rather try doing -
{'eggs': 3} # etc.
That should sort out a lot of problems...
But that's all besides the point of your actual bug. You've got a return in your for-loop in the separate function...This causes the function to return the first value encountered in the loop, and that's it. Once a function's reached a return in exist the function and returns to the outer scope.

Related

for loop through a dictionary - python3

I am just trying to make sense of the piece of code below:
names = [{'name': alice}, {'name':bob}, {'name': david}]
with_comma= ', '.join(name['name'] for name in names[:-1])
What is name['name'] there? How does it extract names from the corresponding dictionaries?
Additionally, what I learned from textbooks is we are supposed to write what will happen after every iteration of for loop "AFTER" the for name in names[:-1], and where is it?
I hope I have written clearly. Thanks for the help.
You need to break down the code in smaller parts and understand the smaller parts to understand the whole.
names is a list containing three dictionaries, each of the dictionaries only contains a single key 'name' with a value. Those values are apparently defined in some other part of the code that we're not given, as these values appear to have been assigned to the variables alice, bob and david.
names[:-1] means 'all the elements of names, except the last', so it's effectively [{'name': alice}, {'name': bob}].
name for name in names[:-1] is a generator, which yields the elements of names[:-1] one at a time. So, it yields {'name': alice} first and then {'name': bob}, and then it completes since there is nothing more to yield.
name['name'] tries to index the variable name with the key 'name'. When name has the value {'name': alice}, name['name'] is whatever the value of alice was when the dictionary was defined.
The .join() method of a string takes an iterable as an argument and puts every element from the iterable together in a new string, with a copy of the original string stuck inbetween each element.
So, this piece of code:
alice = 'Alice'
bob = 'Bob'
david = 'Whatever'
names = [{'name': alice}, {'name': bob}, {'name': david}]
with_comma= ', '.join(name['name'] for name in names[:-1])
Results in with_comma having the value 'Alice, Bob'.
If this is code from a Python training though, I would recommend taking another class or course, because it's not doing a very good job of teaching you Python, throwing in complications like these without explaining the basics.

How to append values to a list in a dictionary while using a while loop?

vacation_poll = {}
name_prompt = "\nWhat is your name? "
vacation_spot_prompt = "\nWhere would you like to go on vacation? "
repeat_prompt = "\nWould you like to continue? (yes/no) "
active = True
while active:
name = input(name_prompt)
vacation_spot = input(vacation_spot_prompt)
vacation_poll[name] = [vacation_spot]
repeat = input(repeat_prompt)
if repeat == 'no':
active = False
for name, spots in vacation_poll.items():
print("\nThese are " + name.title() + "'s places of interest: ")
for spot in spots:
print("\t" + spot.title())
print(vacation_poll)
My goal is to append a new vacation spot in a list inside the dictionary vacation_poll when the same key shows up. So if Joe shows up again after I continue the loop, the new vacation spot should be added to Joe's list of vacation spots, but instead I get it overwritten. I've tried to append using a for loop, but that didn't work either. How could I fix it to append a new value to the list each time the loop is continued?
Have you thought about the schema you'd like to use for the dictionary? From your code, it looks like you're trying to do something like
vacation_poll = {
'Bob': ['Fiji', 'Florida', 'Japan'],
'Joe': ['Disney Land', 'Six Flags', 'Lego Land']
}
When I approach these sorts of problems, usually what I do is set an if statement to check if the key doesn't yet exist in the dictionary and if it doesn't, I initialize it with a list:
if name not in vacation_poll:
vacation_poll[name] = []
This lets me not worry about if the list didn't already exist later in my code and I could do something like
vacation_poll[name].append(vacation_spot)
because after I'd initialized the value associated with name to be a list, I can count on a list being there.
In your case, you might consider using a set instead of a list since it forces only unique values to be stored. This way, if the user enters the same value twice, it'll only record it once even after inserting it again the second time.
You need to use a form of appending to the list. You cannot however just use one of the following:
vacation_poll[name]+=[vacation_spot]
vacation_poll[name].append(vacation_spot)
Doing this will throw an error because when a person's first vacation spot is being added, there is no value indexed at their name in the dictionary. Instead the get(index, default) method is needed.
vacation_poll[name]=vacation_poll.get(name, [])+[vacation_spot]
This will be have as desired. When the key is not yet in the dictionary, get() will return the second parameter, the default value, which is an empty list in this case.

int object is not subscriptable error and list mutability error

I am new to using functions, so I'm really stuck here with a few errors.
When I run the second function, I am getting a 'int object is not subscriptable error'
and When I run the third function, it is changing the list based on the user input as hoped for, but when the program is run again, it shows that the change is not permanent, the list is the same as before the user input change. (its also putting 'None' at the end.
first of all it looks like you reached a point in which you should learn classes and dictionaries , since a lot of this can be simplified if you do learn them. but if you want to keep using a list of lists to store your data here's a way to fix your second function:
this list comprehension behaves as you expect:
[i[products[0].index(inquiry)] for i in products[1:]]
as you wanted products[1:] is a list of the last 2 items in your products list, it looks like so: [[10,30,15], [300, 400, 500]]
thus when you iterate over this list in the first iteration i will be [10,30,15] and in the second iteration it will be [300,400,500]
but the other list comprehensions below it don't behave as you expect,
when you do products[2] or products[1] you don't create a sub-list of your products list, you just get the list in that position, so when you do:
[i[products[0].index(inquiry)] for i in products[2]]
the list i will go over is [300, 400, 500] meaning in the first iteration i will be just the integer 300
since what you want to do is iterate over a single field you should just not use list comprehension and use products[2] and products[1] directly like so :
def retrieve_info():
inquiry = input('Which product would you like information about?')
if inquiry in products[0]:
inquiry_2 = input('Would you like information about the quantity, price, or both?')
if inquiry_2 == 'both':
print([i[products[0].index(inquiry)] for i in products[1:]])
if inquiry_2 == 'price':
print(products[2][products[0].index(inquiry)])
if inquiry_2 == 'quantity':
print(products[1][products[0].index(inquiry)])
if inquiry_2 not in ['both','price','quantity']:
print('error')
else:
print('product not in inventory system')
as for the data storing function, it seems fine to me, try printing products at the start and end of the function to see if it changes

Usage of a random function and lists

Here is my code
N=str(input("Enter the catagory: "))
Countries=["canada","albania","cuba"]
if N=="Countries":
y=random.choice(Countries)
if I do something like this the code takes the elements in the countries but when I try to create a function by using it I fail. For example I have many catogories so I dont want to write if function like 10 times for every catagory.Hence I tried to write it like this
N=str(input("Enter the catagory: "))
Countries=["canada","albania","cuba"]
def cata(N):
y=random.choice(N)
z=len(str(y))
return (z,y)
but at this time when I type countries I only get the letters of the countries so the code refers to the word "countries" but the list name.And I need the elements of the countries list. I am not sure how to fix it
thanks.
Well after the function ends I need both y and z values.
If you have a number of categories, and you need a single function to return a random value from one of those list, depending on the name of the list that you send, I think your best way of doing this is through a dictionary with lists as value. Something like
dic = {
'countries' : ["A","B","C"]
'cities' : ["X","Y","Z"]
}
Now your function can take the name of the list as a parameter, and use it to look up in the dictionary to get the appropriate list, and return a random value from that
N = str(input("Enter the catagory: "))
def cata(n):
y = random.choice(dic[n])
cata(N)
You are confusing a str (a piece of data) with variables and a piece of program code.
If user enters 'Countries' to the input, the string N gets turned into a list ['C', 'o', 'u', ...] inside random.choice(N).
To "fix" your program, you can do it this way:
Countries = ["canada","albania","cuba"]
N = str(input("Enter the catagory: "))
y = random.choice(eval(N))
...
HOWEVER, it is strongly discouraged to apply eval() to a string that user input. Most users can be expected to make mistakes at least some of the time, and a malicious user can abuse it to break your program or even your system.

How can I take a text file and create a triple nested list from it with tkinter python

I'm making a program that allows the user to log loot they receive from monsters in an MMO. I have the drop tables for each monster stored in text files. I've tried a few different formats but I still can't pin down exactly how to take that information into python and store it into a list of lists of lists.
The text file is formatted like this
item 1*4,5,8*ns
item 2*3*s
item 3*90,34*ns
The item # is the name of the item, the numbers are different quantities that can be dropped, and the s/ns is whether the item is stackable or not stackable in game.
I want the entire drop table of the monster to be stored in a list called currentDropTable so that I can reference the names and quantities of the items to pull photos and log the quantities dropped and stuff.
The list for the above example should look like this
[["item 1", ["4","5","8"], "ns"], ["item 2", ["2","3"], "s"], ["item 3", ["90","34"], "ns"]]
That way, I can reference currentDropTable[0][0] to get the name of an item, or if I want to log a drop of 4 of item 1, I can use currentDropTable[0][1][0].
I hope this makes sense, I've tried the following and it almost works, but I don't know what to add or change to get the result I want.
def convert_drop_table(list):
global currentDropTable
currentDropTable = []
for i in list:
item = i.split('*')
currentDropTable.append(item)
dropTableFile = open("droptable.txt", "r").read().split('\n')
convert_drop_table(dropTableFile)
print(currentDropTable)
This prints everything properly except the quantities are still an entity without being a list, so it would look like
[['item 1', '4,5,8', 'ns'], ['item 2', '2,3', 's']...etc]
I've tried nesting another for j in i, split(',') but then that breaks up everything, not just the list of quantities.
I hope I was clear, if I need to clarify anything let me know. This is the first time I've posted on here, usually I can just find another solution from the past but I haven't been able to find anyone who is trying to do or doing what I want to do.
Thank you.
You want to split only the second entity by ',' so you don't need another loop. Since you know that item = i.split('*') returns a list of 3 items, you can simply change your innermost for-loop as follows,
for i in list:
item = i.split('*')
item[1] = item[1].split(',')
currentDropTable.append(item)
Here you replace the second element of item with a list of the quantities.
You only need to split second element from that list.
def convert_drop_table(list):
global currentDropTable
currentDropTable = []
for i in list:
item = i.split('*')
item[1] = item[1].split(',')
currentDropTable.append(item)
The first thing I feel bound to say is that it's usually a good idea to avoid using global variables in any language. Errors involving them can be hard to track down. In fact you could simply omit that function convert_drop_table from your code and do what you need in-line. Then readers aren't obliged to look elsewhere to find out what it does.
And here's yet another way to parse those lines! :) Look for the asterisks then use their positions to select what you want.
currentDropTable = []
with open('droptable.txt') as droptable:
for line in droptable:
line = line.strip()
p = line.find('*')
q = line.rfind('*')
currentDropTable.append([line[0:p], line[1+p:q], line[1+q:]])
print (currentDropTable)

Categories

Resources