Find the value of a specific key in a nested dictionary - python-3.x

I have a nested dictionary
customer_order = {order0
{'Orientation': what_orientation, 'Size': what_size, 'sizecost': size_cost,
'eyelets': how_many_eyelets, 'eyeletcost': eyelet_cost, 'material': what_material,
'materialcost': material_cost, 'ropes': need_ropes, 'ropecost': rope_cost,
'image': need_image, 'imagecost': 0, 'wording': what_wording, 'wordcost':word_cost}
order1{'Orientation': what_orientation, 'Size': what_size, 'sizecost': size_cost,
'eyelets': how_many_eyelets, 'eyeletcost': eyelet_cost, 'material': what_material,
'materialcost': material_cost, 'ropes': need_ropes, 'ropecost': rope_cost,
'image': need_image, 'imagecost': 0, 'wording': what_wording, 'wordcost':word_cost}}
what I need to do is fetch the value of the following keys
sizecost
eyeletcost
materialcost
ropecost
wordcost
how do I loop through to get these values and add them to a running total?
Thanks
I tried the code below but get the error
for key, value in cust_details:
ValueError: too many values to unpack (expected 2)
for cust_order, cust_details in customer_order.items():
print("\nOrder: ", cust_order)
for key, value in cust_details:
if (key == "sizecost"):
totalcosts += value
if (key == "eyeletcost"):
totalcosts += value
if (key == "materialcost"):
totalcosts += value
if (key == "ropecost"):
totalcosts += value
if (key == "wordcost"):
totalcosts += value
totalcost += value

You can use recurssion
def look(key,d,val = None):
if val is None:
val = []
if key in d.keys():
val.append(d.get(key))
else:
for i,j in d.items():
if isinstance(j,dict):
look(key,j,val)
return val
now try calling: look("sizecost", customer_order )

Related

ID inserted automatically in a dictionary and write into a file

I want to create ID for each element inserted in an empty dictionary then write it in a file as in the picture below. But it doesn't work. Any help to fix it?
dict ={}
ids = 0
line_count = 0
fhand = input('Enter the file name:')
fname = open(fhand,'a+')
for line in fname:
if line.split() == []:
ids = 1
else:
line_count +=1
ids = line_count +1
n = int(input('How many colors do you want to add?'))
for i in range (0,n):
dict['ID:'] = ids + 1
dict['Color:'] = input('Enter the color:')
for key,value in dict.items():
s = str(key)+' '+str(value)+'\n'
fname.write(s)
fname.close()
print('Done!') ```
Output should be:
ID : 1
Color: red
ID : 2
Color : rose
ID : 3
Color : blue
Not sure if I got what you meant but...
A dictionary is made of <key, value> pairs.
Let`s suppose you have a dictionary:
thisdict = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
If you want to create a ID for each key (for a specific reason) you could use a for loop like:
for key in thisdict.keys():
createIdFunction(key)
And have a createIdFunction which is going to assign a ID based on whatever you want.
Suggestion: Dictionaries can only hold unique keys, so maybe you could use their own keys as ID.
However if your dictionary is empty, there would be no reason to have a ID for that key, right?
You mean your id is not increased ? I think you did not reassign variable "ids" in loop, you may modify code as below:
dict ={}
ids = 0
line_count = 0
fhand = input('Enter the file name:')
fname = open(fhand,'a+')
for line in fname:
if line.split() == []:
ids = 1
else:
line_count +=1
ids = line_count +1
n = int(input('How many colors do you want to add?'))
for i in range (0,n):
ids += 1 # modified
dict['ID:'] = ids # modified
dict['Color:'] = input('Enter the color:')
for key,value in dict.items():
s = str(key)+' '+str(value)+'\n'
fname.write(s)
fname.close()

Is there a way in which I can iterate over a dictionary and use it in a while loop?

This is how my code looks in python. in the line where df = get_data_df(id,start_at) , instead of defining id one by one, I would like for my program to iterate over id and use it in the program below. please help me with how to iterate over the dictionary (id) and use it in the while loop.
id= {'O': 6232,
'S': 5819,
'S': 5759,
'R': 6056,
'M': 6145,}
whole_df = pd.DataFrame()
start_at = int(datetime(2020,8,1,6,0,0,0, pytz.UTC).timestamp() * 1e6)
while True:
df = get_data_df(id,start_at)
if df.shape[0] <= 1:
break
else:
whole_df = whole_df.append(df)
last_timestamp = whole_df.last_valid_index().timestamp()
start_at = int(last_timestamp * 1e6)
#print(whole_df)
for key in id:
print(key)
Is one way you could do it. Or you Could do it this way
i = 0
while True:
list(id)[i]
i += 1
By Just itterating a index and grabbing a value at each point from that Index
There a multiple ways of iterating over a python dictionary using a for loop:
for key in your_dict:
value = your_dict[key]
print(value)
for value in your_dict.values():
print(value)
for key, value in your_dict.items():
print(key, '=', value)
If you realy want a while loop:
keys = your_dict.keys()
i = 0
while i < len(keys):
value = your_dict[keys[i]]
print(key, '=', value)

how to merge dictionaries of lists with unique key values

I have below dictionaries of lists:
dict1 = {'SourceName': ['PUICUI'], 'EventType': ['XYX'], 'TableName': ['XYX__ct'], 'KeyIndex': ['XYX', 'ZXX']}
dict2 = {'SourceName': ['PUICI2'], 'EventType': ['XYX'], 'TableName': ['ZXX__ct1']}
And my below piece of code is working just as expected.
def combineDictList(*args):
result = {}
for dic in args:
for key in (result.keys() | dic.keys()):
if key in dic:
result.setdefault(key, []).extend(dic[key])
return result
print(combineDictList(dict1, dict2))
which gives me
{'TableName': ['XYX__ct', 'ZXX__ct1'], 'SourceName': ['PUICUI', 'PUICI2'], 'KeyIndex': ['XYX', 'ZXX'], 'EventType': ['XYX', 'XYX']}
But my question is how to print the final result to have unique values, e.g. here EventType has same values.
So, in final result i would only expect the final result to be
{'TableName': ['XYX__ct', 'ZXX__ct1'], 'SourceName': ['PUICUI', 'PUICI2'], 'KeyIndex': ['XYX', 'ZXX'], 'EventType': ['XYX']}
Is there anyway I can achieve this?
Try this
def combineDictList(*args):
result = {}
for dic in args:
for key in (result.keys() | dic.keys()):
if key in dic:
result.setdefault(key, []).extend(dic[key])
result[key] = list(set(result[key]))
return result
print(combineDictList(dict1, dict2))
Use set
Ex:
dict1 = {'SourceName': ['PUICUI'], 'EventType': ['XYX'], 'TableName': ['XYX__ct'], 'KeyIndex': ['XYX', 'ZXX']}
dict2 = {'SourceName': ['PUICI2'], 'EventType': ['XYX'], 'TableName': ['ZXX__ct1']}
def combineDictList(*args):
result = {}
for dic in args:
for k, v in dic.items():
result.setdefault(k, set()).update(v)
# If you need values as list
# result = {k: list(v) for k, v in result.items()}
return result
print(combineDictList(dict1, dict2))
Output:
{'EventType': {'XYX'},
'KeyIndex': {'ZXX', 'XYX'},
'SourceName': {'PUICI2', 'PUICUI'},
'TableName': {'ZXX__ct1', 'XYX__ct'}}

Convert .log record to json

I'm looking to take a log file in the following format and turn it into the json format of the snippet below.
2020:03:29-23:07:22 sslvpnpa ulogd[19880]: id="2001" severity="info" sys="SecureNet" sub="packetfilter" name="Packet dropped" action="drop" fwrule="60001" initf="eth0"
and turn it into the json format of the snippet below.
{"timestamp": "2020:03:29-23:07:22", "object": "sslvpnpa", "code": "ulogd[19880]", "id":"2001", severity="info", sys="SecureNet", sub="packetfilter" ...}
My start was to loop like this:
log_fields = log_row.split()
obj={}
for k in log_fields:
if k.find('=') > -1:
obj[k.split('=')[0]] = k.split('=')[1]
But then i realized some of the values have spaces and that there might be some list comprehension or generator expression that is more efficient or easier to read.
The object/json this generates will then be added to a field in a larger object.
Thanks in advance.
I think this will work out for you:
def split_string(s):
d = {}
ind = 0
split_s = s.split()
while ind < len(split_s):
current_s = split_s[ind]
if "=" in current_s:
key, value, ind = get_full_string(split_s, ind)
d[key] = value
else:
d[f"key{ind}"] = current_s
ind += 1
return d
def get_full_string(split_s, ind):
current_s = split_s[ind]
current_s_split = current_s.split("=")
key = current_s_split[0]
current_value = current_s_split[1]
if current_value[-1] == '"':
current_value = current_value.replace('"', '')
return key, current_value, ind
value_list = [current_value]
ind += 1
while ind < len(split_s):
current_value = split_s[ind]
value_list.append(current_value)
if current_value[-1] == '"':
break
ind += 1
value = " ".join(value_list)
value = value.replace('"', '')
return key, value, ind
Input:
s = '2020:03:29-23:07:22 sslvpnpa ulogd[19880]: id="2001" severity="info" sys="SecureNet" sub="packetfilter" name="Packet dropped" action="drop" fwrule="60001" initf="eth0"'
print(split_string(s))
Output:
{'key0': '2020:03:29-23:07:22', 'key1': 'sslvpnpa', 'key2': 'ulogd[19880]:', 'id': '2001', 'severity': 'info', 'sys': 'SecureNet', 'sub': 'packetfilter', 'name': 'Packet dropped', 'action': 'drop', 'fwrule': '60001', 'initf': 'eth0'}

Recursively iterate through a nested dict and return value of the first matching key

I have a deeply nested dict and need to iterate through it and return the value corresponding to the key argument, second argument of my function.
For example, with
tree = {"a": 12, "g":{ "b": 2, "c": 4}, "d":5}
tree_traverse(tree, "d") should return 5
Here is my code:
def tree_traverse(tree, key):
for k,v in tree.items():
if isinstance(v, dict):
tree_traverse(v, key)
elif k == key:
return v
The problem I have is that this function returns None if it doesnt find the matching key once it's done iterating through the deepest nested dict.
I don't want it to return anything before the matching key is found.
I didn't find a solution in another thread, most of them use print statements and don't return anything so I guess it avoids this issue.
You have to check whether the recursive call actually found something so you can continue the loop. E.g. try the following:
def tree_traverse(tree, key):
if key in tree:
return tree[key]
for v in filter(dict.__instancecheck__, tree.values()):
if (found := tree_traverse(v, key)) is not None:
return found
Here we instantiate an object when the function is created, that all executions of the function will share, called _marker. We return this object if we don't find the key. (You could also use None here, but None is frequently a meaningful value.)
def tree_traverse(tree, key, *, _marker=object()):
for k,v in tree.items():
if isinstance(v, dict):
res = tree_traverse(v, key, _marker=_marker)
if res is not _marker:
return res
elif k == key:
return v
return _marker
def find(tree, key):
_marker = object()
res = tree_traverse(tree, key, _marker=_marker)
if res is _marker:
raise KeyError("Key {} not found".format(key))
return res
I use tree_traverse as a helper function because we want different behaviour at the outermost layer of our recursion (throw an error) than we want inside (return a _marker object)
A NestedDict can solve the problem
from ndicts import NestedDict
def tree_traverse(tree, k):
nd = NestedDict(tree)
for key, value in nd.items():
if k in key:
return value
>>> tree = {"a": 12, "g":{ "b": 2, "c": 4}, "d":5}
>>> tree_traverse(tree, "d")
5
To install ndicts pip install ndicts

Resources