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.
Related
This question already has an answer here:
Efficiently Iterating over dictionary list values by skipping missing values Python 3
(1 answer)
Closed 3 months ago.
I have created a dictionary containing majors and corresponding average salaries. I used a for loop to print the keys of the dictionary (being the majors) for a user to pick from. When I run the for loop at the end of the print statements, I keep getting the key None even when specifying to not print None using an if statement.
Here is the dictionary I defined:
majors = {
'Management Information Systems': 84219,
'Business': 50670,
'Ecology': 58756,
'Psychology': 40858,
'Sociology' : 58678,
}
And here is the for loop I used to print the keys:
def printMajors():
for key in majors.keys():
if key is not None:
print(key)
I also tried deleting the keys with the value None using the following (defined before the print statement):
for key, value in majors.copy().items():
if value is None:
del majors[key]
Output:
Management Information Systems
Business
Ecology
Psychology
Sociology
None // this is unexpected and what I am having trouble with removing
Any help would be much appreciated!
I think you call printMajors() like below:
print(printMajors())
This returns None because your function doesn't return anything (no return statement). The function contains print() inside so there is no need for print() outside anymore.
solution:
printMajors()
majors = {
'Management Information Systems': 84219,
'Business': 50670,
'Ecology': 58756,
'Psychology': 40858,
'Sociology' : 58678,
}
for i,j in majors.items():
print(i)
I am trying to use a dictionary in such a way so that it returns a value dynamically. The following code should print "hello" first, then "world". As of now, it prints "hello" two times. Is there a way for me to use this dictionary dynamically?
val = "hello"
test = {
"A" : val
}
print(test["A"])
val="world"
print(test["A"])
I am thinking that this is not correct use of dictionaries. Could you please the whole task?
You can also check values and change the dictionary value
val = "hello"
test = {
"A" : val
}
print(test["A"])
val="world"
if test["A"]!=val: test["A"]=val
print(test["A"])
instead of val="world" use test["A"] = "world"
val = "world" assigns a new string to the variable, but doesn't change the existing string. The dictionary test however keeps the old string value, not a reference to the val variable. You need to use another mutable data structure if you want to update the dictionary like this. Just for illustration, I show how a list would work:
val = ["hello"]
test = { "A" : val }
print(test["A"][0])
val[0] = "world"
print(test["A"][0])
Unlike a string, a list can be updated. test keeps the same (list) value as val (there is only one list in this example), but val is changed internally.
Note that you must not use val = ["world"], as this would again just assign a new list to val, but leave test unchanged, i.e. still refer to the old list containing "hello".
This question already has answers here:
Find the most common element in a list
(27 answers)
Closed last year.
So i have a response from an api (openweathermap.org) and i have all the {weather} variables in a list. I am trying to get the most common in ["Sunny", "Scattered clouds", "Rainy", "Scattered Clouds"] Just an example but something like that.
I also thought of a way using for loops and dictionaries:
listt = ["R","S","SC","SC"]
dictt = {}
for i in listt:
dict[f"{i}"] +=1
But... Yeah. I know it would not work. I mean, i could hard code dictt but i dont know all the weather conditions from the API.
Is there another way to get the most common String in a list?
i am using one-call api from openweathermap.org
Solution
(Tested in Python 2 and 3)
You could use a dictionary to map the values like what you provided.
Then to get the key or most common string in the dictionary, get the key of the maximum value in the dictionary, like this: (Reference)
listt = ["R","S","SC","SC"]
dictt = {}
for i in listt:
# add to dictionary if it does not exist
if i not in dictt:
# this also does the same thing as 'dict[f"{i}"]'
dictt[i] = 1
# update dictionary
else:
dictt[i] +=1
print(max(dictt))
# 'SC'
Other Remarks
Possible duplicate as commented by #Fareed Khan
You can also utilize Counters in python (as commented by #Ederic Oytas)
from collections import Counter
listt = ["R","S","SC","SC"]
print(max(Counter(listt)))
# 'SC'
I am trying to build a dictionary based on a larger input of text. From this input, I will create nested dictionaries which will need to be updated as the program runs. The structure ideally looks like this:
nodes = {}
node_name: {
inc_name: inc_capacity,
inc_name: inc_capacity,
inc_name: inc_capacity,
}
Because of the nature of this input, I would like to use variables to dynamically create dictionary keys (or access them if they already exist). But I get KeyError if the key doesn't already exist. I assume I could do a try/except, but was wondering if there was a 'cleaner' way to do this in python. The next best solution I found is illustrated below:
test_dict = {}
inc_color = 'light blue'
inc_cap = 2
test_dict[f'{inc_color}'] = inc_cap
# test_dict returns >>> {'light blue': 2}
Try this code, for Large Scale input. For example file input
Lemme give you an example for what I am aiming for, and I think, this what you want.
File.txt
Person1: 115.5
Person2: 128.87
Person3: 827.43
Person4:'18.9
Numerical Validation Function
def is_number(a):
try:
float (a)
except ValueError:
return False
else:
return True
Code for dictionary File.txt
adict = {}
with open("File.txt") as data:
adict = {line[:line.index(':')]: line[line.index(':')+1: ].strip(' \n') for line in data.readlines() if is_number(line[line.index(':')+1: ].strip('\n')) == True}
print(adict)
Output
{'Person1': '115.5', 'Person2': '128.87', 'Person3': '827.43'}
For more explanation, please follow this issue solution How to fix the errors in my code for making a dictionary from a file
As already mentioned in the comments sections, you can use setdefault.
Here's how I will implement it.
Assume I want to add values to dict : node_name and I have the keys and values in two lists. Keys are in inc_names and values are in inc_ccity. Then I will use the below code to load them. Note that inc_name2 key exists twice in the key list. So the second occurrence of it will be ignored from entry into the dictionary.
node_name = {}
inc_names = ['inc_name1','inc_name2','inc_name3','inc_name2']
inc_ccity = ['inc_capacity1','inc_capacity2','inc_capacity3','inc_capacity4']
for i,names in enumerate(inc_names):
node = node_name.setdefault(names, inc_ccity[i])
if node != inc_ccity[i]:
print ('Key=',names,'already exists with value',node, '. New value=', inc_ccity[i], 'skipped')
print ('\nThe final list of values in the dict node_name are :')
print (node_name)
The output of this will be:
Key= inc_name2 already exists with value inc_capacity2 . New value= inc_capacity4 skipped
The final list of values in the dict node_name are :
{'inc_name1': 'inc_capacity1', 'inc_name2': 'inc_capacity2', 'inc_name3': 'inc_capacity3'}
This way you can add values into a dictionary using variables.
I have a dictionary that have the following structure: The key is a link between a source and a destination, the value is the instance of an object wire.
wire_dict = { source1_destination1_1 : object,
source1_destination1_2 : object
source2_destination1_3 : object
source2_destination1_4 : object
source2_destination2_1 : object
source2_destination2_2 : object }
Let's suppose that I only have a destination value, and with that I want to find, perhaps with regular expressions, the key that have the destination1_1. As you can see, same sources can have several destinations, but different sources cannot have the same destinations. So I want to find the key that ends with the destination.
Since the wire_dict could contain a lot of key-value entries, please tell me how this approach can affect the performance of the application. Perhaps I should create another dictionary only for the relationship between source and destination?
UPDATE: I change the dictionary with tuples as keys:
wire_dict = { ('source1','destination1_1') : object1,
('source1','destination1_2') : object2
('source2','destination1_3') : object3
('source2','destination1_4') : object4
('source2','destination2_1') : object5
('source2','destination2_2') : object6 }
The logic of the application is the same. A destination cannot have more than one source. So, only a coincidence should be found when a destination is provided.
Having string searches through dict keys is going to be linear time with standard python dictionaries. But it can be done with dict.keys() and re module as #avim helpfully told.
For the second concern, instead of string keys, how about having tuples as keys:
{(begin, end): connection_object}
It won't speed up at all (search is likely stay linear) but it enables better code behind the logic you want to express.
import re
wire_dict = {'source1_destination1_1' : 'object1',
'source1_destination1_2' : 'object2',
'source2_destination1_3' : 'object3',
'source2_destination1_4' : 'object4',
'source2_destination2_1' : 'object5',
'source2_destination2_2' : 'object6' }
pattern = 'source1_destination1_1'
print [value for key, value in wire_dict.items() if re.search(pattern, key)]
Output:
['object1']
It's easy to run over all dict keys and find the ones that match your pattern, but it's slow for big dicts.
I think you need another dict with keys matching your destinations (as you thought).
You just need str.endswith and to iterate over the dict checking each key.
print([k for k in wire_dict if k.endswith("destination1_1")])
If there is only over one use next and a generator expression:
k = next((k for k in wire_dict if k.endswith("destination1_1")),"")
If you want the value use wire_dict.get(k) in case there is no match and you get an empty string returned from the next call.
In [18]: k = next((k for k in wire_dict if k.endswith("destination1_1")),"")
In [19]: wire_dict[k]
Out[19]: object
In [20]: k
Out[20]: 'source1_destination1_1'
You should also never use dict.keys in python2 unless you actually want a list. You can simply iterate over the dict object to access each key efficiently.
Object oriented programming my friend
class Uberdict():
def init(source, destination, obj):
self.source, self.destination, self.obj = source, destination, obj
def has_destination(destination)
# True or False
return self.desination == destination
def has_source(source)
return self.source == source
wire_object_list = [
# list of the objects
]
# how to create them
example_obj = Uberdict(some_source, some_destination, some_instance)
wire_object_list.append(example_obj)
# filter
example_destination = 'some destination'
filtered_list = [item for item in wire_object_list if item.has_destination(example_destination)
only psuedo code could have errors