How to interpret a string to define a dictionary call? - python

I am attempting to pass in to a function, a string which will be interpreted to determine the desired dictionary call required to update a dictionary.
Here is an example of what I have so far, hard-coded:
import json
from collections import defaultdict
def default_dict():
return defaultdict(default_dict)
def build_dict():
d["a"]["b"]["c"]["d"]["e"]["f"].update({})
d["a"]["b"]["c1"]["d1"].update({})
return json.dumps(d)
d = default_dict()
print build_dict()
But to be useful to me I want to pass in strings to the build_dict() function. Lets call it 's':
for s in ["a/b/c/d/e/f", "a/b/c1/d1"]:
print build_dict(s)
Which should print the following (exactly as it does in the example I hard-coded:
{
"a": {
"b": {
"c": {
"d": {
"e": {
"f": {}
}
}
},
"c1": {
"d1": {}
}
}
}
}
I have to make sure that multiple branches are supported in the way they are (as far as I have tested) in my hard-coded example.
What I am currently attempting:
Midway through constructing this question I found out about dpath, "A python library for accessing and searching dictionaries via /slashed/paths ala xpath". It looks exactly what I need so if I successfully work it out, I will post an answer to this question.

I worked out a solution to my own question.
import json
import dpath.util
def build_dict(viewsDict, viewsList):
for views in viewsList:
viewsDict = new_keys(viewsDict, views)
return viewsDict
def new_keys(viewsDict, views):
dpath.util.new(viewsDict, views, {})
return viewsDict
viewsDict = {}
viewsList = [
"a/b/c/d/e/f",
"a/b/c1/d1"
]
print json.dumps(build_dict(viewsDict, viewsList), indent=4, sort_keys=True)

This builds a dict based on sequence of paths and passes your test case.
It builds a dictionary from up to down, adding a new keys if they are missing, and updating an existing dictionary when they are present.
def build_dict(string_seq):
d = {}
for s in string_seq:
active_d = d
parts = s.split("/")
for p in parts:
if p not in active_d:
active_d[p] = {}
active_d = active_d[p]
return d
expected = {
"a": {
"b": {
"c": {
"d": {
"e": {
"f": {}
}
}
},
"c1": {
"d1": {}
}
}
}
}
string_seq = ["a/b/c/d/e/f", "a/b/c1/d1"]
result = build_dict(string_seq)
assert result == expected

Related

How to find and replace a part of a value in json file in python by taking a result as an argument?

The output of the function I run is in format int. I should replace the number in json file
"x":{..},
"y":{..},
"z":{
"zz":{
"test1": "2010-11",
"test2": "somestring",
},
how do i search and replace the test1 part with the output of the result i get?
What the question is asking for is a 5 step process:
create a (properly formed) dict.
create a function that returns something.
call the function.
change the value of a specific key.
write the new json string.
This is code that will do such:
import json
def some_function():
return 'hello world'
# create a dict
d = { "x":{'a':'b'},
"y":{'a':'b'},
"z":{"zz":{
"test1": "2010-11",
"test2": "somestring",
}
}
}
# call the function
x = some_function()
# change value of a specific key
d['z']['zz']['test1'] = x
# write the new json
j = json.dumps(d, indent=4)
print(j)
Here is the result:
{
"x": {
"a": "b"
},
"y": {
"a": "b"
},
"z": {
"zz": {
"test1": "hello world",
"test2": "somestring"
}
}
}
The answer from #D.L. is correct, so to assign the function result to the dictionary, just assign it like a normal string or variable value.
# pretend I read data from a file, now I have a dictionary
data = {
"x": {},
"y": {},
"z": {
"zz": {
"test1": "2010-11",
"test2": "somestring",
},
},
}
# function returns the val in 'test1' by just running a string replace
# I don't know what your function does, but the
# point is the return value: newval - which is then used directly where you
# called it
def get_results(val):
newval = ''
newval = val.replace('-11', '-10')
return newval
for k,v in data.items():
if k == 'z':
for k2, v2 in data[k].items():
if 'test1' in data[k][k2].keys():
# print(data[k][k2]['test1'])
curval = data[k][k2]['test1']
newval = get_results(curval)
data[k][k2]['test1'] = newval # the return value
You could use the much cleaner code from #D.L. and then assign the updated value.
Assuming I understand the question, you should be able to use the keys in this dictionary/json object:
obj['z']['zz']['test1'] = "2010-10"
obj pertains to the variable name of the object.

Having an issue parsing through this json in python

I have created a var that is equal to t.json. The JSON file is a follows:
{
"groups": {
"customerduy": {
"nonprod": {
"name": "customerduynonprod",
"id": "529646781943",
"owner": "cloudops#coerce.com",
"manager_email": ""
},
"prod": {
"name": "phishing_duyaccountprod",
"id": "241683454720",
"owner": "cloudops#coerce.com",
"manager_email": ""
}
},
"customerduyprod": {
"nonprod": {
"name": "phishing_duyaccountnonprod",
"id": "638968214142",
"owner": "cloudops#coerce.com",
"manager_email": ""
}
},
"ciasuppliergenius": {
"prod": {
"name": "ciasuppliergeniusprod",
"id": "220753788760",
"owner": "cia_developers#coerce.com",
"manager_email": "jarks#coerce.com"
}
}
}
}
my goal was to pars this JSON file and get value for "owner" and output it to a new var. Example below:
t.json = group_map
group_id_aws = group(
group.upper(),
"accounts",
template,
owner = group_map['groups']['prod'],
manager_description = "Groups for teams to access their product accounts.",
The error I keep getting is: KeyError: 'prod'
Owner occurs 4 times, so here is how to get all of them.
import json
# read the json
with open("C:\\test\\test.json") as f:
data = json.load(f)
# get all 4 occurances
owner_1 = data['groups']['customerduy']['nonprod']['owner']
owner_2 = data['groups']['customerduy']['prod']['owner']
owner_3 = data['groups']['customerduyprod']['nonprod']['owner']
owner_4 = data['groups']['ciasuppliergenius']['prod']['owner']
# print results
print(owner_1)
print(owner_2)
print(owner_3)
print(owner_4)
the result:
cloudops#coerce.com
cloudops#coerce.com
cloudops#coerce.com
cia_developers#coerce.com
You get a key error since the key 'prod' is not in 'groups'
What you have is
group_map['groups']['customerduy']['prod']
group_map['groups']['ciasuppliergenius']['prod']
So you will have to extract the 'owner' from each element in the tree:
def s(d,t):
for k,v in d.items():
if t == k:
yield v
try:
for i in s(v,t):
yield i
except:
pass
print(','.join(s(j,'owner')))
If your JSON is loaded in variable data, you can use a recursive function
that deals with the two containers types (dict and list) that can occur
in a JSON file, recursively:
def find_all_values_for_key(d, key, result):
if isinstance(d, dict):
if key in d:
result.append(d[key])
return
for k, v in d.items():
find_all_values_for_key(v, key, result)
elif isinstance(d, list):
for elem in d:
find_all_values_for_key(elem, key, result)
owners = []
find_all_values_for_key(data, 'owner', owners)
print(f'{owners=}')
which gives:
owners=['cloudops#coerce.com', 'cloudops#coerce.com', 'cloudops#coerce.com', 'cia_developers#coerce.com']
This way you don't have to bother with the names of intermediate keys, or in general the structure of your JSON file.
You don't have any lists in your example, but it is trivial to recurse through
them to any dict with an owner key that might "lurk" somewhere nested
under a a list element, so it is better to deal with potential future changes
to the JSON.

Accessing a nested node in a json dictionary with an attribute [duplicate]

I have a dictionary which contains the following json elements.
myjsonDictionary = \
{
"Teams": {
"TeamA": {
"#oid": "123.0.0.1",
"dataRequestList": {
"state": {
"#default": "0",
"#oid": "2"
}
},
"TeamSub": {
"#oid": "3",
"dataRequestList": {
"state": {
"#default": "0",
"#oid": "2"
}
}
}
},
# ....many nested layers
}
}
I have the following issue and am currently very confused on how to solve this problem.
I want to be able to parse this dictionary and get the concatenation of the "#oid" value and the respective "#oid" when I request the "key" such as "TeamA" or "TeamSub".
I have a function which takes in the gettheiDLevelConcatoid(myjsonDictionary, key).
I can call this function like this:
gettheiDLevelConcatoid(myjsonDictionary, key) where "key" is like "TeamA"
And the expected output should be "123.0.0.1.2". Note the 2 appended to the 123.0.0.1.
gettheiDLevelConcatoid(myjsonDictionary, key) where "key" is like TeamSub
Output is "123.0.0.1.3.2". Note the "3.2" added to the "123.0.0.1".
My current implementation:
def gettheiDLevelConcatoid(myjsonDictionary, key)
for item in myjsonDictionary:
if (item == key):
#not sure what to do
I am so lost on how to implement a generic method or approach for this.
With recursive traversal for specific keys:
def get_team_idlvel_oid_pair(d, search_key):
for k, v in d.items():
if k.startswith('Team'):
if k == search_key:
return '{}{}.{}'.format(d['#oid'] + '.' if '#oid' in d else '',
v['#oid'], v['dataRequestList']['state']['#oid'])
elif any(k.startswith('Team') for k_ in v):
return get_team_idlvel_oid_pair(v, search_key)
print(get_team_idlvel_oid_pair(myjsonDictionary['Teams'], 'TeamA'))
print(get_team_idlvel_oid_pair(myjsonDictionary['Teams'], 'TeamSub'))
Sample output:
123.0.0.1.2
123.0.0.1.3.2

Unable to delete a dictionary key inside a json by using the del function. getting a TypeError

Code shorten for this example, I'm iterating through it as if it had multiple keys.
string = '''
{
"people":
{
"a":
{
"parent":
{
"father": "x"
}
}
}
}
'''
data = json.loads(string)
I make sure that my conditional is working, it outputs "ok", so it's fine.
for name in data["people"].values():
if name["parent"]["father"] == "x":
print("ok")
Then I modify the code above to delete that key and I get the following error:
TypeError: unhashable type: 'dict'
for name in data["people"].values():
if name["parent"]["father"] == "x":
del data["people"][name]
What am I doing wrong?
Thank you
You are trying to use name as a key, but name is actually a dictionary, not a string. Use .items() to get both the name and the contents:
for name, contents in data["people"].items():
if contents["parent"]["father"] == "x":
del data["people"][name]
However, note that this will not work either. You can't change the size of a dictionary while iterating it. You can force .items() to fully consume by calling list or similar on it:
for name, contents in list(data["people"].items()):
if contents["parent"]["father"] == "x":
del data["people"][name]
In the end, data will just be {'people': {}}, which I believe is what you want.
Try this:
import json
string = '''
{
"people":
{
"a":
{
"parent":
{
"father": "x"
}
}
}
}
'''
data = json.loads(string)
l = []
for key, values in data["people"].items():
if values["parent"]["father"] == "x":
l.append(key)
for x in l:
data["people"].pop(x)
print(data)

Need help on converting Ruby function to Python function

I'm trying to create a Python function to convert the lists (Objects of arrays in ELK term) to dictionary. I found a sample Ruby function which does that and I'm trying to convert it to Python function for my usage. I'm finding hard time to get the output. The output will be inserted back to Elastic Search.
Ruby Function - I found in Internet
def arrays_to_hash(h)
h.each do |k,v|
# If v is nil, an array is being iterated and the value is k.
# If v is not nil, a hash is being iterated and the value is v.
value = v || k
if value.is_a?(Array)
# "value" is replaced with "value_hash" later.
value_hash = {}
value.each_with_index do |v, i|
value_hash[i.to_s] = v
end
h[k] = value_hash
end
if value.is_a?(Hash) || value.is_a?(Array)
arrays_to_hash(value)
end
end
end
Python Function - I'm trying - Upon seeing the O/P i can see the first list inside the dictionary is getting converted but the nested list inside that is still present
def array_path(my_dict):
for k,v in my_dict.items():
if isinstance(v,list):
print (len(v))
for i, item in enumerate(v):
my_dict2[str(i)] = item
my_dict[k] = my_dict2
elif isinstance(v,dict):
array_path(v)
else:
my_dict[k] = v
Input
{
"foo": "bar",
"test": {
"steps": [
{
"response_time": "100"
},
{
"response_time": "101",
"more_nested": [
{
"hello": "world"
},
{
"hello2": "world2"
}
]
}
]
}
}
**
Expected Output
**
{
"foo": "bar",
"test": {
"steps": {
"0": {
"response_time": "100"
},
"1": {
"response_time": "101",
"more_nested": {
"0": {
"hello": "world"
},
"1": {
"hello2": "world2"
}
}
}
}
}
}
Current O/P
{'0': {'response_time': '100'},
'1': {'more_nested': [{'hello': 'world'}, {'hello2': 'world2'}],
'response_time': '101'}}
the original script stopped its check to list, not implementing a solution for a list of dicts. looks ok now
def array_path(my_dict):
if type(my_dict) is dict:
for k, v in my_dict.items():
my_dict[k] = array_path(v)
elif type(my_dict) is list:
return {str(i): array_path(item) for i, item in enumerate(my_dict)}
return my_dict

Categories

Resources