What is the easiest way to say whether the key div exist or not
di = {
'resp': {
u'frame': {
'html': {
'div': [
u'test1'
]
}
}
}
}
di.get("div","Not found") # prints not found
You need to make a function that recursively check the nested dictionary.
def exists(d, key):
return isinstance(d, dict) and \
(key in d or any(exists(d[k], key) for k in d))
Example:
>>> di = {
... 'resp': {
... u'frame': {
... 'html': {
... 'div': [
... u'test1'
... ]
... }
... }
... }
... }
>>>
>>> exists(di, 'div')
True
>>> exists(di, 'html')
True
>>> exists(di, 'body') # Not exist
False
>>> exists(di, 'test1') # Not a dictionary key.
False
In this precise case, you could use
if 'div' in di['resp'][u'frame']['html']:
More generally, if you don't know (or care) where 'div' is within di, you will need a function to search through the various sub-dictionaries.
You must do a deep search for it.
def rec_search(d):
for key in d.keys():
if key == 'div': return True
for value in d.values():
if isinstance(value, dict) and rec_search(value): return True
return False
First, flatten the dictionary:
def flatten_dict(d):
for k,v in d.items():
if isinstance(v, dict):
for item in flatten_dict(v):
yield [k]+item
else:
yield v
Now check membership in the keys array. Note this will not tell you how many instances of div there are. just that at least 1 is present.
Just trying to solve using regex, which is not the way to solve your problem. But this is fast .
#!/usr/bin/python
di = {
'resp': {
'frame': {
'html': {
'div': [
'test1'
]
}
}
}
}
import re
def check(k):
key = di.keys()
string = str(di.values())
if k in key:
return True
try:
m = re.findall('({[\"\']%s[\"\'])' % k, string)[0]
if m and re.match('{', m):
return True
else:
return False
except:
return False
for i in ['resp', 'abc', 'frame', 'div', 'yopy', 'python', 'test1']:
print i, check(i)
Output:
resp True
abc False
frame True
div True
yopy False
python False
test1 False
Related
How can I call a dictionary recursively to find the last value, assuming dictionaries may have different depths?
a = {
'b': {
'c':'d'
}
}
m = {
'b': {
'c':{
'd':'e'
}
}
}
It's just two examples, I'm trying to get the last value, no matter how deep it's located.
The function doesn't work. How should I pass the final value when it get to the string type?
def get_value(x):
if isinstance(x, dict):
return get_value(x)
else:
return x.get(list(x.keys())[0])
Expected outputs are:
get_value(a) == 'd'
get_value(m) == 'e'
This seems to work:
a = {
'b': {
'c':'d'
}
}
m = {
'b': {
'c':{
'd':'e'
}
}
}
def get_value(x):
if not isinstance(x, dict):
return x
else:
return get_value(x[list(x.keys())[0]])
print (get_value(a))
print (get_value(m))
Output
d
e
def get_value(x):
for key in x.keys():
if isinstance(x[key], dict):
return get_value(x[key])
else:
return x.get(list(x.keys())[0])
The key had to be passed when recursive function was called again.
I have a huge json in the format something like :
{
"Name1": {
"NNum": "11",
"Node1": {
"SubNodeA": "Thomas",
"SubNodeB": "27"
},
"Node2": {
"SubNodeA": "ZZZ",
"SubNodeD": "XXX",
"SubNodeE": "yy"
},
"Node3": {
"child1": 11,
"child2": {
"grandchild": {
"greatgrandchild1": "Rita",
"greatgrandchild2": "US"
}
}
}
}
}
The format or keys are not defined and can go to any depth
I would like to get the list of keys like
keyList= ["Name1.NNum","Name1.Node1.SubNodeA",""Name1.Node1.SubNodeB","Name1.Node2.SubNodeA","Name1.Node2.SubNodeD","Name1.Node2.SubNodeE","Name1.Node3.child1","Name1.Node3.child2.grandchild.greatgrandchild1","Name1.Node3.child2.grandchild.greatgrandchild2"]
A snapshot of the code
def extract_values(obj):
"""Pull all values of specified key from nested JSON."""
arr = []
key_list = []
parent = ""
def extract(obj, arr,parent):
"""Recursively search for values of key in JSON tree."""
if isinstance(obj, dict):
grandparent = ""
for k, v in obj.items():
print ("k ............",k)
parent = grandparent
temp_parent = k
print ("parent >>>>> ",parent)
if isinstance(v, (dict, list)):
parent = temp_parent
print ("IF VALUE DICT .. parent ", parent)
extract(v, arr,parent)
else:
grandparent = parent
parent = parent + "_" + temp_parent
print ("!!!! NOT DICT :).... **** parent ... ", parent)
arr.append(parent)
elif isinstance(obj, list):
for item in obj:
extract(item, arr)
#print ("arr >>>>>>>>>> ", arr)
time.sleep(5)
return arr
results = extract(obj, arr,parent)
return results
but this does not give the expected output.
Expected Output:
keyList= ["Name1.NNum","Name1.Node1.SubNodeA",""Name1.Node1.SubNodeB","Name1.Node2.SubNodeA","Name1.Node2.SubNodeD","Name1.Node2.SubNodeE","Name1.Node3.child1","Name1.Node3.child2.grandchild.greatgrandchild1","Name1.Node3.child2.grandchild.greatgrandchild2"]
Can anybody help me with this.
Thanks in advance
You can use recursion:
d = {'Name1': {'NNum': '11', 'Node1': {'SubNodeA': 'Thomas', 'SubNodeB': '27'}, 'Node2': {'SubNodeA': 'ZZZ', 'SubNodeD': 'XXX', 'SubNodeE': 'yy'}, 'Node3': {'child1': 11, 'child2': {'grandchild': {'greatgrandchild1': 'Rita', 'greatgrandchild2': 'US'}}}}}
def keys(d, c = []):
return [i for a, b in d.items() for i in ([c+[a]] if not isinstance(b, dict) else keys(b, c+[a]))]
result = list(map('.'.join, keys(d)))
Output:
['Name1.NNum', 'Name1.Node1.SubNodeA', 'Name1.Node1.SubNodeB', 'Name1.Node2.SubNodeA', 'Name1.Node2.SubNodeD', 'Name1.Node2.SubNodeE', 'Name1.Node3.child1', 'Name1.Node3.child2.grandchild.greatgrandchild1', 'Name1.Node3.child2.grandchild.greatgrandchild2']
def getKeys(object, prev_key = None, keys = []):
if type(object) != type({}):
keys.append(prev_key)
return keys
new_keys = []
for k, v in object.items():
if prev_key != None:
new_key = "{}.{}".format(prev_key, k)
else:
new_key = k
new_keys.extend(getKeys(v, new_key, []))
return new_keys
This solution assumes that the inner types that might have children are dictionaries.
You can do simple recursion:
d = {
"Name1": {
"NNum": "11",
"Node1": {
"SubNodeA": "Thomas",
"SubNodeB": "27"
},
"Node2": {
"SubNodeA": "ZZZ",
"SubNodeD": "XXX",
"SubNodeE": "yy"
},
"Node3": {
"child1": 11,
"child2": {
"grandchild": {
"greatgrandchild1": "Rita",
"greatgrandchild2": "US"
}
}
}
}
}
def get_keys(d, curr_key=[]):
for k, v in d.items():
if isinstance(v, dict):
yield from get_keys(v, curr_key + [k])
elif isinstance(v, list):
for i in v:
yield from get_keys(i, curr_key + [k])
else:
yield '.'.join(curr_key + [k])
print([*get_keys(d)])
Prints:
['Name1.NNum', 'Name1.Node1.SubNodeA', 'Name1.Node1.SubNodeB', 'Name1.Node2.SubNodeA', 'Name1.Node2.SubNodeD', 'Name1.Node2.SubNodeE', 'Name1.Node3.child1', 'Name1.Node3.child2.grandchild.greatgrandchild1', 'Name1.Node3.child2.grandchild.greatgrandchild2']
What about this?
from collections import Mapping
def extract_paths(base_path, dd):
new_paths = []
for key, value in dd.items():
new_path = base_path + ('.' if base_path else '') + key
if isinstance(value, Mapping):
new_paths.extend(extract_paths(new_path, value))
else:
new_paths.append(new_path)
return new_paths
extract_paths('', your_dict)
Use isinstance to check the dict or not called by function recursively. If dict append to path recursively else print the path
def print_nested_keys(dic,path=''):
for k,v in dic.items():
if isinstance(v,dict):
path+=k+"."
yield from print_nested_keys(v,path)
else:
path+=k
yield path
Output:
>>> [*print_nested_keys(d)] # Here, d is your nested dictionary
['Name1.NNum',
'Name1.NNumNode1.SubNodeA',
'Name1.NNumNode1.SubNodeASubNodeB',
'Name1.NNumNode1.Node2.SubNodeA',
'Name1.NNumNode1.Node2.SubNodeASubNodeD',
'Name1.NNumNode1.Node2.SubNodeASubNodeDSubNodeE',
'Name1.NNumNode1.Node2.Node3.child1',
'Name1.NNumNode1.Node2.Node3.child1child2.grandchild.greatgrandchild1',
'Name1.NNumNode1.Node2.Node3.child1child2.grandchild.greatgrandchild1greatgrandchild2']
There are various API endpoints that I call that return response objects of varying complexities and I need to parse through an unknown level of nested data structures of either lists and/or dictionaries.
For example, if I get back a response and convert the json to a dictionary here:
response = {
"key1":"value1",
"key2":"value2",
"key3":"value3",
"key4":[
"item1",
"item2"
],
"key5":"value4",
"key6":"value5",
"key7":{
"key1":"value1",
"key2":"value2",
"key3":"value3",
"key4":"value4",
"key5":"value5",
"key6":"value6"
},
"key8":"value6"
}
My method below will work, since its only dealing with lists or dictionaries one level deep in nesting:
def check_values(payload):
values = []
for value in payload.values():
if isinstance(value, list):
for item in value:
values.append(bool(item))
elif isinstance(value, dict):
for nested_value in value.values():
values.append(bool(nested_value))
else:
values.append(bool(value))
if all(values):
return True
return False
print(check_values(response))
However, if I have something like this, my method above wouldn't work:
response = {
"key1": {"foobar" : ["a", None, {"xyz": 123}]},
"key2":"value2",
"key3":"value3",
"key4":[
[4, 5, 6],
[[[[[[[[[[[[[[[[[[[["hi"]]]]]]]]]]]]]]]]]]]]
],
"key5":"value4",
"key6":"value5",
"key7":{
"key1":"value1",
"key2":"value2",
"key3":"value3",
"key4":"value4",
"key5":"value5",
"key6":"value6"
},
"key8":"value6"
}
Any ideas or suggestions would be greatly appreciated. =)
f_response = {
'val0':[1,2,3,[True],[42]],
'val1':{}, # assuming {} ,[] are Falsey values bool({}) False
'val2':['x'],
'val3':[[[False]]]
}
t_response = {
'val0':[1,2,3,[True],[42]],
'val1':{1:[43]},
'val2':['x'],
'val3':[[[True,[True]]]]
}
response = {
"key1": {"foobar" : ["a", None, {"xyz": 123}]},
"key2":"value2",
"key3":"value3",
"key4":[
[4, 5, 6],
[]
],
"key5":"value4",
"key6":"value5",
"key7":{
"key1":"value1",
"key2":"value2",
"key3":"value3",
"key4":"value4",
"key5":"value5",
"key6":"value6"
},
"key8":"value6"
}
def check_values(payload):
if isinstance(payload, dict):
if payload != {}:
for value in payload.values():
if isinstance(value, list):
if not check_values(value):
return False
elif isinstance(value, dict):
if not check_values(value):
return False
else:
if not bool(value):
return False
else:
return False
elif isinstance(payload, list):
if payload != []:
for value in payload:
if isinstance(value, list):
if not check_values(value):
return False
elif isinstance(value, dict):
if not check_values(value):
return False
else:
if not bool(value):
return False
else:
return False
return True
print(check_values(f_response)) #False
print(check_values(t_response)) #True
print(check_values(response)) #False
I have a dict, lets say mydict
I also know about this json, let's say myjson:
{
"actor":{
"name":"",
"type":"",
"mbox":""
},
"result":{
"completion":"",
"score":{ "scaled":"" },
"success":"",
"timestamp":""
},
"verb":{
"display":{
"en-US":""
},
"id":""
},
"context":{
"location":"",
"learner_id": "",
"session_id": ""
},
"object":{
"definition":{
"name":{
"en-US":""
}
},
"id":"",
"activity_type":""
}
}
I want to know if ALL of myjson keys (with the same hierarchy) are in mydict. I don't care if mydict has more data in it (it can have more data). How do I do this in python?
Make a dictionary of myjson
import json
with open('myjson.json') as j:
new_dict = json.loads(j.read())
Then go through each key of that dictionary, and confirm that the value of that key is the same in both dictionaries
def compare_dicts(new_dict, mydict):
for key in new_dict:
if key in mydict and mydict[key] == new_dict[key]:
continue
else:
return False
return True
EDIT:
A little more complex, but something like this should suit you needs
def compare(n, m):
for key in n:
if key in m:
if m[key] == n[key]:
continue
elif isinstance(n[key], dict) and isinstance(m[key],dict):
if compare(n[key], m[key]):
continue
else:
return False
else:
return False
return True
If you just care about the values and not the keys you can do this:
>>> all(v in mydict.items() for v in myjson.items())
True
Will be true if all values if myjson are in mydict, even if they have other keys.
Edit: If you only care about the keys, use this:
>>> all(v in mydict.keys() for v in myjson.keys())
True
This returns true if every key of myjson is in mydict, even if they point to different values.
I have a list of lists containing key and value like so:
[
['mounts:device', '/dev/sda3'],
['mounts:fstype:[0]', 'ext1'],
['mounts:fstype:[1]', 'ext3']
]
Well I can easily change the list to this
(Lists arent seperated by ':')
[
['mounts:device', '/dev/sda3'],
['mounts:fstype[0]', 'ext1'],
['mounts:fstype[1]', 'ext3']
]
Whatever suits better for this problem:
Problem is to create a dictionary:
{
'mounts': {
'device': '/dev/sda3',
'fstype': [
'ext1',
'ext3'
]
}
It should also be possible to have lists in lists for example:
['mounts:test:lala:fstype[0][0]', 'abc']
or
['mounts:test:lala:fstype:[0]:[0]', 'abc']
This is what I have so far:
def unflatten(pair_list):
root = {}
for pair in pair_list:
context = root
key_list = pair[0].split(':')
key_list_last_item = key_list.pop()
for key in key_list:
if key not in context:
context[key] = {}
context = context[key]
context[key_list_last_item] = pair[1]
return root
Based on this answer https://stackoverflow.com/a/18648007/5413035 but as requested I need recursivness and lists in the mix
Thanks in advance
Here is a solution using a tree of dict:
import collections
def tree():
return collections.defaultdict(tree)
def unflatten(pair_list):
root = tree()
for mount, path in pair_list:
parts = mount.split(":")
curr = root
for part in parts[:-1]:
index = int(part[1:-1]) if part[0] == "[" else part
curr = curr[index]
part = parts[-1]
index = int(part[1:-1]) if part[0] == "[" else part
curr[index] = path
return root
With the following input:
pair_list = [
['mounts:device', '/dev/sda3'],
['mounts:fstype:[0]', 'ext1'],
['mounts:fstype:[1]', 'ext3'],
['mounts:test:lala:fstype:[0]:[0]', 'abc']
]
You'll get:
{
"mounts": {
"fstype": {
"0": "ext1",
"1": "ext3"
},
"test": {
"lala": {
"fstype": {
"0": {
"0": "abc"
}
}
}
},
"device": "/dev/sda3"
}
}
Then you can use the recursive function make_listbellow to turn the integer indexes in a list.
def make_list(root):
if isinstance(root, str):
return root
keys = list(root.keys())
if all(isinstance(k, int) for k in keys):
values = [None] * (max(keys) + 1)
for k in keys:
values[k] = make_list(root[k])
return values
else:
return {k: make_list(v) for k, v in root.items()}
Here is the result with the pair_list:
flat = unflatten(pair_list)
flat = make_list(flat)
You'll get:
{'mounts': {'device': '/dev/sda3',
'fstype': ['ext1', 'ext3'],
'test': {'lala': {'fstype': [['abc']]}}}}
Is it fine?
input1=[
['mounts:device', '/dev/sda3'],
['mounts:fstype:[0]', 'ext1'],
['mounts:fstype:[1]', 'ext3']
]
input2={x[1]:x[0].split(':')[1] for x in input1}
input3=['ext3', 'ext1', '/dev/sda3']
input4=['fstype', 'fstype', 'device']
res={}
for x,y in zip(input3, input4):
res.setdefault(y,[]).append(x)
res1=res.keys()
res2=res.values()
res3=[x[0] for x in res2 if len(x)==1]+[x for x in res2 if len(x)>1]
result=dict(zip(res1,res3))
print result
Output :
{'device': '/dev/sda3', 'fstype': ['ext3', 'ext1']}