I have below dictionary (generated from a report, so the structure can change).
I need to go to the depth of the dictionary, find the id which in this case is 'id': u'ef3c8cf1-0987-4e56-a6d5-763c42be1f75', (there can be more than 1), delete that id and then move to one level up and repeat the same till I get to the top id which I finally delete. Since there is a dependency, I need to delete the orphan id first and then move to the top.
Any help is appreciable. If any other file/information is needed, please let me know.
{
'id': u'4c31d813-a989-47dd-b01b-9a27b8db2dfc',
'snapshots':
[
{
'id': u'3ddc7ddd-02ca-4669-a0cb-fb0d56a4a6f5',
'volumes':
[
{
'id': u'5488de90-50dc-4d72-a6aa-c995422fa179',
'snapshots': [],
'snapshot_id': u'3ddc7ddd-02ca-4669-a0cb-fb0d56a4a6f5'
},
{
'id': u'e566645f-4fb3-4778-be67-447a5bdd678d',
'snapshots':
[
{
'id': u'd637f6ea-4a41-448c-874f-ffe624ddc597',
'volumes':
[
{
'id': u'ef3c8cf1-0987-4e56-a6d5-763c42be1f75',
'snapshots': [],
'snapshot_id': u'd637f6ea-4a41-448c-874f-ffe624ddc597'
}
]
}
],
'snapshot_id': u'3ddc7ddd-02ca-4669-a0cb-fb0d56a4a6f5'},
{
'id': u'196483ee-4f21-4d83-8e15-8caea532b2ab',
'snapshots': [],
'snapshot_id': u'3ddc7ddd-02ca-4669-a0cb-fb0d56a4a6f5'
}
]
}
],
'snapshot_id': None
}
Python code
oh=openstack_helper.OpenstackHelper()
def get_objects(item):
items=None
if item == 'stacks':
items=oh.get_stacks()
if item == 'volumes':
items=oh.get_volumes()
if item == 'snapshots':
items=oh.get_snapshots()
return items
def dep_graph(volumes,snapshots,snapshot_id=None):
vol_list=[]
for volume in volumes:
if volume.snapshot_id == snapshot_id:
info={'id':volume.id,'snapshot_id':volume.snapshot_id,'snapshots':[],
}
vol_list.append(info)
for snapshot in snapshots:
for volume in vol_list:
snap_list=[]
if snapshot.volume_id == volume['id']:
info={'id':snapshot.id, 'volumes':[]}
info['volumes'].extend(dep_graph(volumes,snapshots,snapshot.id))
volume['snapshots'].append(info)
return vol_list
if __name__ == '__main__':
volumes = get_objects('volumes')
snapshots = get_objects('snapshots')
output = dep_graph(volumes, snapshots)
print output
Here is the solution I propose:
def remove_id(data):
if isinstance(data, List):
return [remove_id(sub_data) for sub_data in data]
if isinstance(data, Dict):
return {key: remove_id(value) for key, value in data.items()
if key != 'id'}
return data
And the result:
{'snapshot_id': None,
'snapshots': [{'volumes': [{'snapshot_id': '3ddc7ddd-02ca-4669-a0cb-fb0d56a4a6f5',
'snapshots': []},
{'snapshot_id': '3ddc7ddd-02ca-4669-a0cb-fb0d56a4a6f5',
'snapshots': [{'volumes': [{'snapshot_id': 'd637f6ea-4a41-448c-874f-ffe624ddc597',
'snapshots': []}]}]},
{'snapshot_id': '3ddc7ddd-02ca-4669-a0cb-fb0d56a4a6f5',
'snapshots': []}]}]}
Related
I have a json like:
pd = {
"RP": [
{
"Name": "PD",
"Value": "qwe"
},
{
"Name": "qwe",
"Value": "change"
}
],
"RFN": [
"All"
],
"RIT": [
{
"ID": "All",
"IDT": "All"
}
]
}
I am trying to change the value change to changed. This is a dictionary within a list which is within another dictionary. Is there a better/ more efficient/pythonic way to do this than what I did below:
for key, value in pd.items():
ls = pd[key]
for d in ls:
if type(d) == dict:
for k,v in d.items():
if v == 'change':
pd[key][ls.index(d)][k] = "changed"
This seems pretty inefficient due to the amount of times I am parsing through the data.
String replacement could work if you don't want to write depth/breadth-first search.
>>> import json
>>> json.loads(json.dumps(pd).replace('"Value": "change"', '"Value": "changed"'))
{'RP': [{'Name': 'PD', 'Value': 'qwe'}, {'Name': 'qwe', 'Value': 'changed'}],
'RFN': ['All'],
'RIT': [{'ID': 'All', 'IDT': 'All'}]}
How do I replace the json_object's blookup with blookup_values based on the ID's in the json blookup. I tried the below code by removing the ID's which are not present in the json_object['blookup']. The below code doesn't work. Could anyone please help.
blookup_values = [
{
"id":"123",
"name":"abc",
"date":"somedate",
"time":"sometime"
},
{
"id":"456",
"name":"def",
"date":"somedate",
"time":"sometime"
},
{
"id":"789",
"name":"ghi",
"date":"somedate",
"time":"sometime"
},
{
"id":"9999",
"name":"mmmmmm",
"date":"somedate",
"time":"sometime"
},
{
"id":"8888",
"name":"nnnnnn",
"date":"somedate",
"time":"sometime"
}
]
json_object = {
"id":"id_value",
"blookup": [{
"id":"123",
"type":"dddd"
},
{
"id":"456",
"type":"eeeee"
}
]
}
Code
result = [obj for obj in blookup_values if obj['id'] != json_object['blookup']]
Expected result
result = {
"id":"id_value",
"blookup": [{
"id":"123",
"name":"abc",
"date":"somedate",
"time":"sometime"
},
{
"id":"456",
"name":"def",
"date":"somedate",
"time":"sometime"
}
]
}
You have to get the id key from the json_object dictionaries:
result = [obj for obj in blookup_values if obj['id'] in [i["id"] for i in json_object['blookup']]]
First convert blookup_values into a dictionary keyed by id. Then you can replace json_object['blookup'] with a list comprehension made from this.
blookup_dict = {value['id']: value for value in blookup_values}
json_object['blookup'] = [blookup_dict[item['id']] for item in json_object['blookup']]
I’m not sure I completely understand what you are trying to do but what I gather is that you want to get the objects in blookup that do not have any of the same ids as the objects in json_objects. Is that correct?
Try to first get the id values of each object in json_object['blookup']. For example:
json_object_ids = [obj['id'] for obj in json_object['blookup']]
Next, filter the objects in blookup by slightly altering your list comprehension:
result = [obj for obj in blookup_values if obj['id'] not in json_object_ids]
The output would look something like this:
[{'id': '789', 'name': 'ghi', 'date': 'somedate', 'time':
'sometime'}, {'id': '9999', 'name': 'mmmmmm', 'date': 'som
edate', 'time': 'sometime'}, {'id': '8888', 'name': 'nnnnn
n', 'date': 'somedate', 'time': 'sometime'}]
I have a deeply nested dictionary (arbitrary keys and values) like:
data = {
'a': {
'path': '/a/a.txt'
},
'b': {
'b1': {
'path': '/b/b1/b1.txt'
},
'b2': {
'path': '/b/b2/b2.txt'
}
}
'c': {
'c1': {
'c12': {
'path': '/c/c1/c12/c12.txt'
}
},
'c2': {
'c22': {
'path': '/c/c1/c22/c22.txt'
}
},
'c3': {
'c32': {
'path': '/c/c1/c32/c32.txt'
}
}
}
.
.
.
}
My goal is to prepend every value in the dictionary with a specific path. So basically take in the data above, operate on it:
def prepend(value, data):
return magic
data = prepend('predir/z', data)
and have the resulting dict look like:
data = {
'a': {
'path': 'predir/z/a/a.txt'
},
'b': {
'b1': {
'path': 'predir/z/b/b1/b1.txt'
},
'b2': {
'path': 'predir/z/b/b2/b2.txt'
}
}
'c': {
'c1': {
'c12': {
'path': 'predir/z/c/c1/c12/c12.txt'
}
},
'c2': {
'c22': {
'path': 'predir/z/c/c1/c22/c22.txt'
}
},
'c3': {
'c32': {
'path': 'predir/z/c/c1/c32/c32.txt'
}
}
}
.
.
.
}
I know I can use recursion to loop through the dict like so:
def prepend(directory, config):
for k, v in config.items():
if isinstance(v, dict):
prepend(directory, v)
else:
# do something
But, I'm not able to change the values during iteration. Any and all help is greatly appreciated! Thank you!
In the else branch, just add the prefix to the existing value, and store it in the key :
def prepend(directory, config):
for k, v in config.items():
if isinstance(v, dict):
prepend(directory, v)
else:
config[k] = directory + v
return config
You have to use
else:
config[k] = directory + config[k]
or
else:
config[k] = directory + v
and it will change value directly in original data so you don't need return config.
BTW: If you want to keep original data then you would have to create new_config in function.
def prepend(directory, config):
new_config = {}
for k, v in config.items():
if isinstance(v, dict):
new_config[k] = prepend(directory, v)
else:
new_config[k] = directory + v
return new_config
new_data = prepend('predir/z', data)
print(data)
print(new_data)
I am retrieving a record set from a database.
Then using a for statement I am trying to construct my data to match a 3rd party API.
But I get this error and can't figure it out:
"errorType": "TypeError", "errorMessage": "list indices must be
integers, not str"
"messages['english']['merge_vars']['vars'].append({"
Below is my code:
cursor = connect_to_database()
records = get_records(cursor)
template = dict()
messages = dict()
template['english'] = "SOME_TEMPLATE reminder-to-user-english"
messages['english'] = {
'subject': "Reminder (#*|code|*)",
'from_email': 'mail#mail.com',
'from_name': 'Notifier',
'to': [],
'merge_vars': [],
'track_opens': True,
'track_clicks': True,
'important': True
}
for record in records:
record = dict(record)
if record['lang'] == 'english':
messages['english']['to'].append({
'email': record['email'],
'type': 'to'
})
messages['english']['merge_vars'].append({
'rcpt': record['email']
})
for (key, value) in record.iteritems():
messages['english']['merge_vars']['vars'].append({
'name': key,
'content': value
})
else:
template['other'] = "SOME_TEMPLATE reminder-to-user-other"
close_database_connection()
return messages
The goal is to get something like this below:
messages = {
'subject': "...",
'from_email': "...",
'from_name': "...",
'to': [
{
'email': '...',
'type': 'to',
},
{
'email': '...',
'type': 'to',
}
],
'merge_vars': [
{
'rcpt': '...',
'vars': [
{
'content': '...',
'name': '...'
},
{
'content': '...',
'name': '...'
}
]
},
{
'rcpt': '...',
'vars': [
{
'content': '...',
'name': '...'
},
{
'content': '...',
'name': '...'
}
]
}
]
}
This code seems to indicate that messages['english']['merge_vars'] is a list, since you initialize it as such:
messages['english'] = {
...
'merge_vars': [],
...
}
And call append on it:
messages['english']['merge_vars'].append({
'rcpt': record['email']
})
However later, you treat it as a dictionary when you call:
messages['english']['merge_vars']['vars']
It seems what you want is something more like:
vars = [{'name': key, 'content': value} for key, value in record.iteritems()]
messages['english']['merge_vars'].append({
'rcpt': record['email'],
'vars': vars,
})
Then, the for loop is unnecessary.
What the error is saying is that you are trying to access an array element with the help of string not index (int).
I believe your mistake is in this line:
messages['english']['merge_vars']['vars'].append({..})
You declared merge_vars as array like so:
'merge_vars': []
So, you either make it dict like this:
'merge_vars': {}
Or, use it as array:
messages['english']['merge_vars'].append({..})
Hope it helps
Your issues, as the Error Message is saying, is here: messages['english']['merge_vars']['vars'].append({'name': key,'content': value})
The item messages['english']['merge_vars'] is a list and thus you're trying to access an element when you do something like list[i] and i cannot be a string, as is the case with 'vars'. You probably either need to drop the ['vars'] part or set messages['english']['merge_vars'] to be a dict so that it allows for additional indexing.
I am creating dict in python and this dict may includes lists and sub dicts . If I want to check a key exist in any dict first I have reach to that dict and then only I can check wether the key exists or not . But is there any way that I can check key existence using parent dict only means if parent dict have any child dicts then searching goes to every level and let me know that wether the key exist in entire dict or not and then using that key I can insert or delete elments in that dict which includes that key.
e.g., I have this
[
{
'groupName': u'MainMenu_1',
'menuItems': [
{
'action': u'/home\r\n',
'sub_1': [
],
'id': 1L,
'name': u'Home\r\n'
},
{
'action': u'/inventory',
'sub_2': [
],
'id': 2L,
'name': u'Inventory\r\n'
},
{
'action': u'/accounting\r\n',
'sub_3': [
{
'action': u'/gl\r\n',
'name': u'GL\r\n',
'sub_4': [
]
},
{
'action': u'/ap\r\n',
'name': u'AP\r\n',
'sub_5': [
]
},
{
'action': u'/ar\r\n',
'sub_6': [
],
'name': u'AR\r\n'
}
],
'id': 3L,
'name': u'Accounting\r\n'
},
{
'action': u'/crm\r\n',
'sub_8': [
],
'id': 8L,
'name': u'CRM\r\n'
}
]
},
{
'groupName': u'MainMenu_2',
'menuItems': [
{
'action': u'/iv-receive\r\n',
'sub_9': [
],
'id': 9L,
'name': u'Receiving\r\n'
},
{
'action': u'/iv-shipping\r\n',
'sub_10': [
],
'id': 10L,
'name': u'Shipping\r\n'
}
]
}
]
Now if in above example I want to search for any key like sub_1 , sub_3, sub_6 then how I can search for this key
We can search for all qualifying dictionary recursively. The following implementation appends all references of such dictionaries to the list found:
def recursive_search(items, key):
found = []
for item in items:
if isinstance(item, list):
found += recursive_search(item, key)
elif isinstance(item, dict):
if key in item:
found.append(item)
found += recursive_search(item.values(), key)
return found
found = recursive_search(items, 'sub_9')
def flatten(obj):
if isinstance(obj, list):
result = set()
for e in obj:
result = result.union(flatten(e))
return result
elif isinstance(obj, dict):
return set(obj.keys()) | flatten(obj.values())
else:
return {obj}
You can alternatively flatten the list/dictionary into a set, and do as many searches as you want quickly.
print(flatten(lst))
set([1, 2, 3, u'/inventory', 8, 9, 'menuItems', u'/home\r\n', u'/ar\r\n', u'AP\r\n', u'/accounting\r\n', 'id', u'MainMenu_2', u'Receiving\r\n', u'Home\r\n', u'MainMenu_1', u'/iv-shipping\r\n', 'groupName', 10, u'AR\r\n', u'Accounting\r\n', u'/ap\r\n', u'Inventory\r\n', u'CRM\r\n', u'/crm\r\n', u'/iv-receive\r\n', 'sub_10', u'GL\r\n', u'Shipping\r\n', 'name', 'sub_2', 'sub_3', 'sub_1', 'sub_6', 'sub_4', 'sub_5', 'action', 'sub_8', 'sub_9', u'/gl\r\n'])