I am trying to make a dictionary of sorts using tuples. The idea is to store a word along with its description in a tuple. The tuple then goes into a list. After that, I'm supposed to be able to look up the meaning of a word in the dictionary by typing the word I want a description of.
My problem is to extract only the description part of the tuple from the list and print only that based on what word the user wants to look up. I do have a function that seems to work for making the tuples and storing them in the list but I think that function also is wrong.
This is as far as I have been able to come:
def tuples():
dictionary = []
while True:
print("\n--- Menu for dictionary ---\n Choose 1 to insert a word\n Choose 2 to lookup a word\n Choose 3 to quit\n")
answer = input("Write your answer here: ")
if answer == "1":
insert(dictionary)
elif answer == "2":
lookup(dictionary)
elif answer == "3":
break
else:
print("\nTry again!\n")
def insert(dictionary):
word = input("What word would you like to add: ")
des = input("Type a description of that word: ")
info = (word, des)
dictionary.append(info)
def lookup(dictionary):
word = input("What word do you want to lookup: ")
place = dictionary.index(word)
print("\nDescription of", word,":", dictionary[place], "\n")
Similar to the other answer, this example loops through the list of tuples examining the word part of the tuple to get to the description part. It differs in a number of respects, but the most important difference is that it uses tuple unpacking versus subscripting to get the contents of the tuple. To illustrate the key concepts I left out the user input part.
Note: If the list of tuples was long enough, you would want to consider sorting it and using something like the the bisect standard library to more efficiently search it and update it.
Example:
dictionary = [("cat", "Four legs, scratches."), ("dog", "Four legs, wags."), ("gerbil", "Four legs, kangaroo-like.")]
def find_description(dictionary, search_term):
# Note use of automatic tuple "unpacking"
for word, description in dictionary:
if word == search_term:
print(f"Description of {word}: {description}")
break
else: # no-break
print(f"Could not find {search_term} in dictionary.")
find_description(dictionary, "gerbil")
find_description(dictionary, "hamster")
Output:
Description of gerbil: Four legs, kangaroo-like.
Could not find hamster in dictionary.
I think you can achieve what you are trying to do by modifying your lookup function
to use a generator expression to search the dictionary list for the query. I got your example to work with the following modification to lookup():
def lookup(dictionary):
word = input("What word do you want to lookup: ")
place = next((i for i, v in enumerate(dictionary) if v[0] == word), None)
print("\nDescription of", word,":", dictionary[place][1], "\n")
If you are concerned with runtime I would recommend abstracting out the (word, des) tuple out to a class that could be hashable such that you can use a dictionary as your dictionary, utilizing the faster lookup. This also would solve the issue of duplicate entries.
Related
I am creating a dictionary with "Full Name": "Birthday" for numerous people as an exercise.
The program should ask
"Who's birthday do you want to look up?"
I will input a name, say "Benjamin Franklin"
And it will return his birthday: 1706/01/17.
Alright, the problem I am encountering is name capitalization.
How can I input "benjamin franklin" and still find "Benjamin Franklin" in my dictionary? I am familiar with .lower() and .upper() functions, however I am not able to implement them correctly, is that the right way to approach this problem?
Here is what I have
bday_dict = {"Person1": "YYYY/MM/DD1",
"Person2": "YYYY/MM/DD2",
"Benjamin Franklin": "1706/01/17"}
def get_name(dict_name):
name = input("Who's birthday do you want to look up? > ")
return name
def find_bday(name):
print(bday_dict[name])
find_bday(get_name(bday_dict))
The best way to do this is to keep the keys in your dictionary lowercase. If you can't do that for whatever reason, have a dictionary from lowercase to the real key, and then keep the original dictionary.
Otherwise, Kraigolas's solution works well, but it is O(N) whereas hashmaps are supposed to be constant-time, and thus for really large dictionaries the other answer will not scale.
So, when you are setting your keys, do bday_dict[name.lower()] = value and then you can query by bday_dict[input.lower()].
Alternatively:
bday_dict = {"John": 1}
name_dict = {"john": "John"}
def access(x):
return bday_dict[name_dict[x.lower()]]
Probably the most straight forward way I can think of to solve this is the following:
def get_birthday(name):
global bday_dict
for person, bday in bday_dict.items():
if name.lower() == person.lower():
return bday
return "This person is not in bday_dict"
Here, you just iterate through the entire dictionary using the person's name paired with their birthday, and if we don't find them, just return a message saying we don't have their birthday.
If you know that all names will capitalize the first letter of each word, you can just use:
name = ' '.join([word.capitalize() for word in name.split()])
then you can just search for that. This is not always the case. For example, for "Leonardo da Vinci" this will not work, so the original answer is probably the most reliable way to do this.
One final way to do this would be to just store the names as lowercase from the beginning in your dictionary, but this might not be practical when you want to draw a name from the dictionary as well.
Depending what your exercise allows, I would put the names in the dictionary as all lowercase or uppercase. So:
bday_dict = {"person1": "YYYY/MM/DD1",
"person2": "YYYY/MM/DD2",
"benjamin franklin": "1706/01/17"}
And then look up the entered name in the dictionary like this:
def find_bday(name):
print(bday_dict[name.lower()])
You may also want to do a check that the name is in the dictionary beforehand to avoid an error:
def find_bday(name):
bday = bday_dict.get(name.lower(), None)
if bday:
print(bday)
else:
print("No result for {}.".format(name))
I have been having trouble trying to delete an element or pair from my dictionary. It is supposed to delete both the father and the son when you type in the son's name, but it always produces this error:
Traceback (most recent call last):
File "C:\Users\jam7733\Desktop\whos ur daddy.py", line 23, in <module>
daddy()
File "C:\Users\jam7733\Desktop\whos ur daddy.py", line 20, in daddy
if del_son in fathers:
TypeError: unhashable type: 'list'
here is the code i have:
def daddy():
fathers = {'johnny':'john Dupuis','alex':'jordan belfort','henry':'daniel plainview','mike':'brian cranston','max':'fred man','benny':'nick flick','billy':'robert kardashian'}
choice = raw_input("do you want to: a)add a father-son pair,b)delete a pair, c)replace a pair,d)look up father-son pair, or e)look for grandfather")
if choice == 'd':
name = raw_input("what is the first name of the child? ")
if name in fathers:
print name,"is the child of",fathers[name]
else:
print "sorry, we do not have this name listed, please try again."
daddy()
if choice == "a":
new_dad = raw_input("what is the name of the new dad?")
new_son = raw_input("what is the name of the son?")
fathers[new_dad]=new_son
if choice == "b":
print"Here are the names of the fathers that you can delete: "
print fathers
del_son = raw_input("what father/son pair do you want to delete?(type first name of son").split(" ")
if del_son in fathers:
del fathers[del_son]
daddy()
As said in the comments by #kindall and #PadraicCunningham, del_son is a list:
del_son = raw_input("what father/son pair do you want to delete?(type first name of son").split(" ")
because here you split its name with a space. Given your code I believe this is a mistake, or there's something you don't understand when you wrote that line.
In python you cannot use a list as the key of a dict, because a dict need all its keys to be non-mutable, in order to ensure that a given key is unique. And in python, lists and dicts are mutable. That means that when you do:
i = 1
i = 2
i is only a reference to the int object instanced with the value 1. When you assign 2 to i, the former instance with value 1 is being forgotten about, and will be collected by the garbage collector. But when you do:
l = []
l.append(1)
l.append(2)
then you've made a reference from l to a list object, which you modified to contain two values: 1 and 2. So now, imagine that you want to index a value with a list in a dict, and you do:
d = {}
l1 = [3,1]
l2 = [3,4]
d[l1] = 'foo'
d[l2] = 'bar'
naively, there's no reason why that wouldn't work and be:
{[1,4]: 'foo', [3,4]: 'bar'}
but then what if you do:
l1.remove(1)
l1.append(4)
Then how could the dict still work, as the dict would then become:
{[3,4]: 'foo', [3,4]: 'bar'}
Hopefully, you got the tuple type which is non-mutable and hashable:
d = {(3,1): 'foo', (3,4): 'bar}
So you might simply want to not .split() it. You might want to strip() it (which will remove any leading and trailing whitespace character).
So here you go:
del_son = raw_input("what father/son pair do you want to delete?(type first name of son").strip()
if del_son in fathers.keys():
del fathers[del_son]
my two cents: to make it slightly more explicit, you'd better use del_son in fathers.keys(). It's actually the same as what you wrote, simply for readability it's easier, as del_son in fathers is misleading (which one could read as: "is the coder removing a son from the list of fathers? WTH?", whereas adding the .keys() will read "Ah! The coder is removing a father from a son→father mapping! Makes sense!")
HTH
A dictionary cannot have a key of type list because the keys MUST be immutable. You can, however, use another immutable type (like a tuple), but that's peripheral to the larger issue. The problem is that you split the name of the son when there is no need to.
del_son = raw_input("what father/son pair do you want to delete?(type first name of son").split(" ")
This is always going to return a list. When you type:
del fathers[del_son]
it indexes the fathers dict with a key of a list, which is not allowed. Simply remove the .split(" ") after the raw_input and it should work.
For the del_son input, you're assigning the result of raw_input("...").split(" "). That split() returns a list. So del_son becomes a list, which can't be used for dictionary keys.
What you want, in this case, is just the first result of the split, so raw_input("...").split(" ")[0]:
del_son = raw_input("what father/son pair ...").split(" ")[0]
That's the first item in the returned list (index 0). Then del_son is just the first element, and a string.
If that raw_input...split...[0] seems too long, you can leave that line as how you have it now and change the next bit to:
if del_son[0] in fathers:
del fathers[del_son[0]]
You are confusing yourself with regard to your index, thereby confusing your dict into a list, since it is now mutable. Looking for a list in a dict, which a list cannot be hashed!
Hey everyone I'm trying to write a program in Python that acts as a quiz game. I made a dictionary at the beginning of the program that contains the values the user will be quizzed on. Its set up like so:
PIX0 = {"QVGA":"320x240", "VGA":"640x480", "SVGA":"800x600"}
So I defined a function that uses a for loop to iterate through the dictionary keys and asks for input from the user, and compares the user input to the value matched with the key.
for key in PIX0:
NUM = input("What is the Resolution of %s?" % key)
if NUM == PIX0[key]:
print ("Nice Job!")
count = count + 1
else:
print("I'm sorry but thats wrong. The correct answer was: %s." % PIX0[key] )
This is working fine output looks like this:
What is the Resolution of Full HD? 1920x1080
Nice Job!
What is the Resolution of VGA? 640x480
Nice Job!
So what I would like to be able to do is have a separate function that asks the question the other way, providing the user with the resolution numbers and having the user enter the name of the display standard. So I want to make a for loop but I don't really know how to (or if you even can) iterate over the values in the dictionary and ask the user to input the keys.
I'd like to have output that looks something like this:
Which standard has a resolution of 1920x1080? Full HD
Nice Job!
What standard has a resolution of 640x480? VGA
Nice Job!
I've tried playing with for value in PIX0.values() and thats allowed me to iterate through the dictionary values, but I don't know how to use that to "check" the user answers against the dictionary keys. If anyone could help it would be appreciated.
EDIT: Sorry I'm using Python3.
Depending on your version:
Python 2.x:
for key, val in PIX0.iteritems():
NUM = input("Which standard has a resolution of {!r}?".format(val))
if NUM == key:
print ("Nice Job!")
count = count + 1
else:
print("I'm sorry but thats wrong. The correct answer was: {!r}.".format(key))
Python 3.x:
for key, val in PIX0.items():
NUM = input("Which standard has a resolution of {!r}?".format(val))
if NUM == key:
print ("Nice Job!")
count = count + 1
else:
print("I'm sorry but thats wrong. The correct answer was: {!r}.".format(key))
You should also get in the habit of using the new string formatting syntax ({} instead of % operator) from PEP 3101:
https://www.python.org/dev/peps/pep-3101/
You could search for the corresponding key or you could "invert" the dictionary, but considering how you use it, it would be best if you just iterated over key/value pairs in the first place, which you can do with items(). Then you have both directly in variables and don't need a lookup at all:
for key, value in PIX0.items():
NUM = input("What is the Resolution of %s?" % key)
if NUM == value:
You can of course use that both ways then.
Or if you don't actually need the dictionary for something else, you could ditch the dictionary and have an ordinary list of pairs.
You can just look for the value that corresponds with the key and then check if the input is equal to the key.
for key in PIX0:
NUM = input("Which standard has a resolution of %s " % PIX0[key])
if NUM == key:
Also, you will have to change the last line to fit in, so it will print the key instead of the value if you get the wrong answer.
print("I'm sorry but thats wrong. The correct answer was: %s." % key )
Also, I would recommend using str.format for string formatting instead of the % syntax.
Your full code should look like this (after adding in string formatting)
PIX0 = {"QVGA":"320x240", "VGA":"640x480", "SVGA":"800x600"}
for key in PIX0:
NUM = input("Which standard has a resolution of {}".format(PIX0[key]))
if NUM == key:
print ("Nice Job!")
count = count + 1
else:
print("I'm sorry but that's wrong. The correct answer was: {}.".format(key))
If all your values are unique, you can make a reverse dictionary:
PIXO_reverse = {v: k for k, v in PIX0.items()}
Result:
>>> PIXO_reverse
{'320x240': 'QVGA', '640x480': 'VGA', '800x600': 'SVGA'}
Now you can use the same logic as before.
Create the opposite dictionary:
PIX1 = {}
for key in PIX0.keys():
PIX1[PIX0.get(key)] = key
Then run the same code on this dictionary instead (using PIX1 instead of PIX0).
BTW, I'm not sure about Python 3, but in Python 2 you need to use raw_input instead of input.
I have asked a similar question like this before, so I do apologise, but I read the task back and had misread the original requirements.
So, based on the feedback that I received here, this is the code that I used:
def task3():
classList = {}
classSearch = input("Which class would you like to interrogate? ")
try:
with open("answers " + classSearch + ".txt", 'rb') as handle:
classList = pickle.loads(handle.read())
except IOError as error:
print ("Sorry, this file does not exist")
sortOption = int(input("Would you like sort the students in alphabetical order? Enter 1\n Would you like to sort the students by highest score? Enter 2 \nWould you like to sort students by their average score?Enter 3\n"))
if sortOption == 1:
x = sorted(classList.items())
for key, value in x:
value.sort()
value.reverse()
print (x)
So what I actually need to do is to output the highest score of each student, sorted alphabetically by name. Inside the classList dictionary is a students name and then a list containing the last 3 scores that they received on the quiz. This is obviously repeated for multiple students. Any help would be massively appreciated.
Something like this should work, assuming the inputs are completely unsorted:
for name,highscore in [(student,max(classList[student])) for student in sorted(classList.keys())]:
print name,highscore
ETA:
As requested, providing an explanation.
classList is a dict, with each member consisting of a key (student's name) and a value (list of scores for that student).
My suggested code iterates over a pre-sorted list comprehension of tuples containing the student name and highest score for that student, printing each in turn.
The list comprehension does all the work here.
classList.keys() produces a list containing the student names. The built-in sorted function returns the same sorted in alphabetical order, in this case.
The list comprehension is like a for loop, iterating over the list of keys, and building a list of tuples.
You could also have said
sortedNames = sorted(classList.keys())
for student in sortedNames:
high_score = max(classList[student])
print student, high_score
I'm fairly new to Python but am ok with programming (although haven't done any for about 5 years).
I've searched but can't find anything to answer my problem:
I have a number of lists, each with values in them, I'm trying to create a generic function that takes 2 values that searches a list, the 2 values are obviously the list name, and the string to search for in that list:
list0 = ["name","date","cat","dog"]
list1 = ["house","chair","table"]
list2 = ["tv","dvd","computer","mouse"]
usersearchlist = raw_input("Enter list name: ")
usersearchitem = raw_input("Enter item to search for: ")
def searchmemory(usersearchlist,usersearchitem):
return usersearchlist.index(usersearchitem)
I then call the function:
print "I found", searchmemory(usersearchlist,usersearchitem)
I'm getting the "ValueError: substring not found" because the function call is taking the literal string passed into the function and not referencing the value contained inside of it.
Hope that makes sense, am I doing something totally wrong?
try
lists = {"list0" : ["name","date","cat","dog"],
"list1" : ["house","chair","table"],
"list2" : ["tv","dvd","computer","mouse"]}
usersearchlist = raw_input("Enter list name: ")
usersearchitem = raw_input("Enter item to search for: ")
def searchmemory(usersearchlist, usersearchitem):
if (usersearchlist in lists and usersearchitem in lists[usersearchlist]):
return lists[usersearchlist].index(usersearchitem)
else:
return -1
This stores all the lists in a dictionary and checks if the value exists first so you shouldn't get a ValueError
I would prefer to put the lists in a dictionary similar to #SimplyKiwi 's answer.
Alternatively, you can also achieve it with globals():
print "I found", searchmemory(globals().get(usersearchlist, []), usersearchitem)
Be warned though in this case, you are implicitly giving the user access to all the global variables. In most scenario, this is not what you would want the users to be able to do.