I have started learning python. In this code, I am trying to print the Birthdate of the inputted user along with his/her name. I am using a dictionary to achieve this functionality. Below is my code snippet
n=input("Enter Name: ")
def birth():
dict1={{"name":"X","birthdate":"16-June-1989"},{"name":"Y","birthdate":"23-08-1990"}}
if dict1["name"]==n:
print(dict1["name"]+"'s birth was on " +dict1["birthdate"])
else:
print("Not in database")
birth()
My expected output should look like this on inputting X:
X's birthdate was on 16-June-1989
But I am getting below error, I tried an online search, but I wanted to understand what I am missing here. I am sure I will be getting many comments. But I am also sure that many will provide constructively and learning suggestions.
File "main.py", line 8, in <module>
birth()
File "main.py", line 3, in birth
dict1={{"name":"X","birthdate":"16-June-1989"},{"name":"Y","birthdate":"23-08-1990"}}
TypeError: unhashable type: 'dict'
You are getting the error because dictionary variable dict1 can't parse its own elements,so you need to create an variable/object which can parse the elements of the dictionary which is done by parse variable p
n=input("Enter name: ")
def birth(n):
dict1=[{"name":"X","birthdate":"16-June-1989"},{"name":"Y","birthdate":"23-08-1990"}]
for p in dict1:
if p["name"]==n:
print(p["name"]+"'s birth was on " +p["birthdate"])
break;
else:
print("Not in database")
break;
birth(n)
The way you defined your dict1 is incorrect. It should be like this:
In [1131]: def birth(n):
...: #dict1={{"name":"X","birthdate":"16-June-1989"},{"name":"Y","birthdate":"23-08-1990"}}
...: dict1=[{"name":"X","birthdate":"16-June-1989"},{"name":"Y","birthdate":"23-08-1990"}]
...: for d in dict1:
...: if d["name"]==n:
...: print(d["name"]+"'s birth was on " +d["birthdate"])
...: else:
...: print("Not in database")
...:
In [1132]: birth(n)
X's birth was on 16-June-1989
Also, it would make more sense if you pass the user input n as a parameter to your function birth. Then call the method like birth(n).
Otherwise, the method is tightly coupled with the variable named n.
That's because you have a wrong dict initialization.
In python 3+ curly brackets are used not only for dict literal but and for set literal. You can get more info in this question.
For example:
# that will be a dict:
d = {"name": "My name", "birthdate": "16-June-1989"}
# and that will be a set:
d = {"name", "birthdate"}
# your line 3 has set initialization, which contains 2 dicts of user info:
dict1={{"name":"X","birthdate":"16-June-1989"},{"name":"Y","birthdate":"23-08-1990"}}
One more problem that in Python sets must contain only hashable elements and dict is not hashable. Here is the explanation.
So you should change your dict1 variable type to list or tuple. If you need more info about the difference between lists, sets and tuples here is a link to python documentation about data structures.
And also your function will print something for every entry in your database. I think that you need only 1 print after function execution.
So your function should look like that:
def birth(name):
database = [{"name": "X", "birthdate": "16-June-1989"},
{"name": "Y", "birthdate": "23-08-1990"}]
found = False
for entry in database:
if entry["name"] == name:
print(entry["name"] + "'s birth was on " + entry["birthdate"])
found = True
break
if not found:
print("Not in database")
birth('X')
# Will print: X's birth was on 16-June-1989
birth('My name is')
# Will print: Not in database
Make sure that your dictionary definition is correct. It should have the form:
thisdict = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
You can not use a dictionary as a key in a dictionary.
From the Python documentation:
dictionaries are indexed by keys, which can be any immutable type; strings and numbers can always be keys. Tuples can be used as keys if they contain only strings, numbers, or tuples; if a tuple contains any mutable object either directly or indirectly, it cannot be used as a key. You can’t use lists as keys, since lists can be modified in place using index assignments, slice assignments, or methods like append() and extend().
Related
I'm super new to python so i don't know anything even the basics of basics function so could anyone tell me how do i match value to my dictionary and where did i do wrong
#dictionary
id = {"2":"30", "3":"40"}
#json display from web
messages: {"id":2,"class":0,"type":1,"member":"N"}
if messages['id'] == id: # << this part i think i'm doing it wrong too because it prints error`
print ('the new id value from dictionary') # << what do i put in here`
else:
print ('error')
Use if str(messages['id']) in id instead of if messages['id'] == id
to check if a values is a key in a dict you can do it like this:
if messages['id'] in id:
but it will not work right away in your case.
The values in the json data are integers so you need to convert them to match the dict.
you will end up with this
if str(messages['id']) in id:
full code:
id = {"2": "30", "3": "40"}
messages = {"id":2,"class":0,"type":1,"member":"N"}
if str(messages['id']) in id:
print(id[str(messages['id'])])
else:
id[str(messages['id'])] = '50'
The error occurs because you need to use an = to assign variables:
messages = {"id":2,"class":0,"type":1,"member":"N"}
instead of
messages: {"id":2,"class":0,"type":1,"member":"N"}
Concerning what you want to achieve, you are trying to access a dictionary value by using a default value ("error") in case the key doesn't exist. You can use dict.get for that, rather than if-else:
#dictionary
id_dict = {"2":"30", "3":"40"}
#json display from web
messages = {"id":2,"class":0,"type":1,"member":"N"}
print(id_dict.get(messages['id'], "error"))
Caveats:
Don't use id as a variable name, as it is a Python built-in keyword.
If the id_dict has string keys, you also need to use strings to access it, i.e. messages = {"id":2 ... will not give you the value "30" for id_dict = {"2":"30", "3":"40"}.
You need to convert the value to check to string in order to perform a valid comparison. Also, you should not use Python keywords as name variables to avoid additional issues:
id_dict = {"2":"30", "3":"40"}
#Use = to assign variables, not :
messages = {"id":2,"class":0,"type":1,"member":"N"}
if str(messages['id']) in id_dict:
print ('the new id value from dictionary')
else:
print ('error')
Output:
the new id value from dictionary
I have the following JSON structure given in a python script:
print("Producers: ", metadata['plist']['dict']['array'][2]['dict']['string'])
The Problem is that I don't have a single entry on that field, instead I have multiple ones.
Please also see the RAW JSON here: https://pastebin.com/rtTgmwvn
How can I pull out these entries as a comma separated string for [2] which is the producers field?
Thanks in advance
You're almost there:
you can do something like this
print("Producers: ", ", ".join(i["string"] for i in metadata['plist']['dict']['array'][2]['dict'])
to break down the solution... your "dict" element in the JSON is actually a list of "dict", and therefore you can simply iterate over this list:
metadata['plist']['dict']['array'][2]['dict']
where each element is an actual dict with a "string" key.
Update
The format of the JSON is so tahat in some cases it is a list, and in some cases it is a single element. In that case, I would suggest writing a small function or use an if statement that handles each situation:
def get_csv(element):
if isinstance(element, dict):
return element["string"]
return ", ".join(i["string"] for i in element)
# and you would use it like so:
print("Producers: ", get_csv(metadata['plist']['dict']['array'][2]['dict']))
The following should do the trick:
def get_producer_csv(data):
producers = []
dict = data["plist"]["dict"]["array"][2]["dict"]
for dict_entry in dict:
producers.append(dict_entry["string"])
return ",".join(producers)
For your example, it returns the following: "David Heyman,David Barron,Tim Lewis"
This question already has answers here:
Access nested dictionary items via a list of keys?
(20 answers)
Closed 2 years ago.
Apologies if this is really simple, but I can't seem to get it going.
My application is working with nested dicts. For example: -
test = {
"alpha": "first",
"beta": {
"mid": {
"message": "winner winner"
}
},
"omega": "last"
}
Now I need to be able retrieve values out of that dict using variable the value of which is being dynamically constructed based on myriad other factors. So essentially I'm trying to put together a way to generate the key that I need depending on variable factors.
For example if I get back from one function "beta", from another, "mid" and from another "message", the best I can think to do is assemble a string which looks like the key path.
So for example:
current = '["beta"]["mid"]["message"]'
How can I use current to get back the "winner winner" string?
I have tried things like:-
v = '"[beta"]["mid"]"message]"'
print(test[v])
But just hitting Key errors.
Must be an easy way to get values based on calculated keys. Would appreciate a shove in the right direction.
[Question text updated]
Yes, I know I can do:
val = test['beta']['mid']['message']
And get back the value, I'm stuck on how to use the generated string as the the key path. Apologies for not being clear enough.
import re
t = '["beta"]["mid"]["message"]'
val = None
for i in re.findall(r'"([^"]+)"', t):
if(val == None):
val = test.get(i)
else:
val = val.get(i)
print(val)
or,
from functools import reduce
import operator
import re
t = '["beta"]["mid"]["message"]'
reduce(operator.getitem, re.findall(r'"([^"]+)"', t), test)
winner winner
Store the three keys as three different variables rather than as a string:
key_one = 'beta'
key_two = 'mid'
key_three = 'message'
v = test[key_one][key_two][key_three]
If you already have the keys in the string format you describe, then do some string splitting to produce three variables like the above. You don't want to eval the code as it creates a security risk.
current = '["beta"]["mid"]["message"]'
keys = [w.strip('[]"') for w in current.split('"]["')]
test[keys[0]][keys[1]][keys[2]]
# or
# key_one = keys[0]
# key_two = keys[1]
# key_three = keys[2]
# v = test[key_one][key_two][key_three]
This should do it:
v = test['beta']['mid']['message']
print(v)
Note: The issue is you're indexing the dictionary with a string in your example, not a set of keys.
Basically I am trying to find a way to get the key of a value from a dictionary by searching the value.
people = {
"Sarah" : "36",
"David" : "42",
"Ricky" : "13"
}
user_input = ('Enter the age of the individual") #The user enters the
#value
key_to_output = (...) #The variable that would contain the key value
print(key_to_output)
For example in the dictionary above if the user enters "36", they would be returned have "Sarah" returned. The dictionary I am using will never have a overlapping values so don't worry about any issues that would cause.
Also, because my python knowledge isn't very advanced it would be much appreciated if the responses were kept quite amateur so I can understand them properly.
You can invert the dictionary as so -
people_inv = {v:k for k,v in people.items()}
Now say your user inputted 36,
user_input = "36"
people_inv[user_input] # this will give Sarah
If the values are not unique like in the example below, you can do this -
people = {"Sarah":36, "Ricky":36, "Pankaj":28}
people_inv= {}
for k,v in people.items():
people_inv.setdefault(v, []).append(k)
people_inv["36"]
Output
['Sarah', 'Ricky']
The easyest way would be to itterate over the values like this.
def find_key(value, people):
for name in people:
if people[name] == value:
return name
If you are trying to get mutliple keys I would try:
def find_key(value, people):
names = []
for name in people:
if people[name] == value:
names.append(name)
return names
I need to make a function that updates tuples in a list of tuples. The tuples contain transactions, which are characterised by ammount, day, and type. I made this function that should completely replace a tuple with a new one, but when I try to print the updated list of tuples I get the error:
TypeError: tuple indices must be integers or slices, not str
The code:
def addtransaction(transactions, ammount, day, type):
newtransactions = {
"Ammount": ammount,
"Day": day,
"Type": type
}
transactions.append(newtransaction)
def show_addtransaction(transactions):
Ammount = float(input("Ammount: "))
Day = input("Day: ")
Type = input("Type: ")
addtransaction(transactions, ammount, day, type)
def show_all_transaction(transactions):
print()
for i, transaction in enumerate(transactions):
print("{0}. Transaction with the ammount of {1} on day {2} of type: {3}".format(
i + 1,
transaction['Ammount'], ; Here is where the error occurs.
transaction['Day'],
transaction['Type']))
def update_transaction(transactions): ; "transactions" is the list of tuples
x = input("Pick a transaction by index:")
a = float(input("Choose a new ammount:"))
b = input("Choose a new day:")
c = input("Choose a new type:")
i = x
transactions[int(i)] = (a, b, c)
addtransaction(transactions, 1, 2, service)
show_all_transaction(transactions)
update_transaction(transactions)
show_all_transaction(transactions)
A tuple is basically only a list, with the difference that in a tuple you cannot overwrite a value in it without creating a new tuple.
This means you can only access each value by an index starting at 0, like transactions[0][0].
But as it appears you should actually use a dict in the first place. So you need to rewrite update_transaction to actually create a dict similar to how addtransaction works. But instead of adding the new transaction to the end you just need to overwrite the transaction at the given index.
This is what update_transaction already does, but it overwrites it with a tuple and not a dict. And when you print it out, it cannot handle that and causes this error.
Original answer (Before I knew the other functions)
If you want to use strings as indexes you need to use a dict. Alternatively you can use namedtuple which are like tuples but it also has an attribute for each value with the name you defined before. So in your case it would be something like:
from collections import namedtuple
Transaction = namedtuple("Transaction", "amount day type")
The names given by the string used to create Transaction and separated by spaces or commas (or both). You can create transactions by simply calling that new object. And accessing either by index or name.
new_transaction = Transaction(the_amount, the_day, the_type)
print(new_transaction[0])
print(new_transaction.amount)
Please note that doing new_transaction["amount"] will still not work.
This is not a generic answer, I'll just mention it if someone bumps into the same problem.
As stated before, tuples are addressed by integer e.g. my_tuple[int] or slice my_tuple[int1:int2].
I ran into trouble when I ported code from Python2 to Python3. The original code used somthing like my_tuple[int1/int2], this worked in Python2 since division int/int results in int.
in Python3 int/int results in a floating point number.
I had to fix the code to my_tuple[int1//int2] to get the python2 behavior.