Python3 remove entire nested dictionary - python

{'result':{'result':[
{
'Company':{
'PostAddress':None
},
'ExternalPartnerProperties':None,
'Id':123456,
'Level':'Level1',
'Name':'Name1',
'ParentId':456789,
'State':'InTrial',
'TrialExpirationTime':1435431669
},
{
'Company':{
'PostAddress':None
},
'ExternalPartnerProperties':None,
'Id':575155,
'Level':'Level2',
'Name':'Name2',
'ParentId':456789,
'State':'InTrial',
'TrialExpirationTime':1491590226
},
{
'Company':{
'PostAddress':None
},
'ExternalPartnerProperties':None,
'Id':888888,
'Level':'Level2',
'Name':'Name3',
'ParentId':456789,
'State':'InProduction',
'TrialExpirationTime':1493280310
},
My code:
for i in partner_output['result']['result']:
if "InProduction" in i['State']:
del i['Company'], i['ExternalPartnerProperties'], i['Id'], i['Level'], i['Name'], i['ParentId'], i['State'], i['TrialExpirationTime']
If I do this, then I return the following result
{'result': {'result': [{
'Company':{
'PostAddress':None
},
'ExternalPartnerProperties':None,
'Id':123456,
'Level':'Level1',
'Name':'Name1',
'ParentId':456789,
'State':'InTrial',
'TrialExpirationTime':1435431669
},
{
'Company':{
'PostAddress':None
},
'ExternalPartnerProperties':None,
'Id':575155,
'Level':'Level2',
'Name':'Name2',
'ParentId':456789,
'State':'InTrial',
'TrialExpirationTime':1491590226
},
{},
but the total number of items is still 3 ... the 3rd container is just empty, but still a container. How can I delete the 3rd container all together?
I cannot use:
for i in partner_output['result']['result']:
if "InProduction" in i['State']:
del partner_output['result'][i]
because I get the error:
TypeError: unhashable type: 'dict'
So I don't know what to do now :-(

You can use a list comprehension to replace the whole list, keeping the other items:
partner_output['result']['result'] = [
i for i in partner_output['result']['result']
if i['State'] != "InProduction"
]
Note that the test for the filter has been reversed; you want to keep all items that do not have 'State' set to InProduction. Alternatively, keep values where the state is set to InTrial:
partner_output['result']['result'] = [
i for i in partner_output['result']['result']
if i['State'] == "InTrial"
]
Your second attempt failed because you tried to use i, a reference to a dictionary, as a key in the outer partner_output['result'] dictionary. If you wanted to delete something from the partner_output['result']['result'] list, you'd have to use the integer index (del partner_output['result']['result'][2]), but you can't do that in a loop because that has consequences for the for loop progress across the list.

Related

How to retrieve data from this list

This list how to retrieve only problems by using python.
[{"ordination": [{"condition": "system_drive_free_space < 10000","match": true,"problems": [{"id": "disk_cleanup","point": "/remote_action/disk_cleanup/hgk5255sfghjkd516465s"
}]},{"condition": "total_drive_free_space < 20000","match": true,"problems": [{ "id": "disk_cleanup","point": "/remote_action/disk_cleanup/h41525c274558hgfdbd3b"}]}]},{
"ordination": [{"condition": "\"action:Get Startup Impact/HighImpactCount\" > 0","match": true}]},{"ordination": [{"condition": "average_network_response_time > 30000",
"match": true},{"condition": "network_availability_level != high","match": true}] }]
For example the output like this
"problems": [{"id": "disk_cleanup","point": "/remote_action/disk_cleanup/hgk5255sfghjkd516465s" }]
you can try something
items = [{"ordination": [{"condition": "system_drive_free_space < 10000", "match": True, "problems": [
{"id": "disk_cleanup", "point": "/remote_action/disk_cleanup/hgk5255sfghjkd516465s"}]},
{"condition": "total_drive_free_space < 20000", "match": True, "problems": [
{"id": "disk_cleanup", "point": "/remote_action/disk_cleanup/h41525c274558hgfdbd3b"}]}]},
{"ordination": [{"condition": "action: Get Startup Impact / HighImpactCount> 0", "match": True}]},
{"ordination": [{"condition": "average_network_response_time > 30000", "match": True},
{"condition": "network_availability_level != high", "match": True}]}]
for item in items:
for ordination in item['ordination']:
print(ordination.get('problems'))
It prints None for ordinations without problems.
If that array is stored in a variable called list, (e.g. list = [{ordination...) then you can use this code to retrieve the value of problems:
problems = list[0].get("ordination")[0].get("problems")
print(problems)
This should print out the list which is stored the problems section.
if your data is in a variable named data, then try this:
for item in data:
for inside_item in item.get("ordination", []):
for inside_value in inside_item.get("problems", []):
print(inside_value[0]["id"])

Automatically entering next JSON level using Python in a similar way to JQ in bash

I am trying to use Python to extract pricePerUnit from JSON. There are many entries, and this is just 2 of them -
{
"terms": {
"OnDemand": {
"7Y9ZZ3FXWPC86CZY": {
"7Y9ZZ3FXWPC86CZY.JRTCKXETXF": {
"offerTermCode": "JRTCKXETXF",
"sku": "7Y9ZZ3FXWPC86CZY",
"effectiveDate": "2020-11-01T00:00:00Z",
"priceDimensions": {
"7Y9ZZ3FXWPC86CZY.JRTCKXETXF.6YS6EN2CT7": {
"rateCode": "7Y9ZZ3FXWPC86CZY.JRTCKXETXF.6YS6EN2CT7",
"description": "Processed translation request in AWS GovCloud (US)",
"beginRange": "0",
"endRange": "Inf",
"unit": "Character",
"pricePerUnit": {
"USD": "0.0000150000"
},
"appliesTo": []
}
},
"termAttributes": {}
}
},
"CQNY8UFVUNQQYYV4": {
"CQNY8UFVUNQQYYV4.JRTCKXETXF": {
"offerTermCode": "JRTCKXETXF",
"sku": "CQNY8UFVUNQQYYV4",
"effectiveDate": "2020-11-01T00:00:00Z",
"priceDimensions": {
"CQNY8UFVUNQQYYV4.JRTCKXETXF.6YS6EN2CT7": {
"rateCode": "CQNY8UFVUNQQYYV4.JRTCKXETXF.6YS6EN2CT7",
"description": "$0.000015 per Character for TextTranslationJob:TextTranslationJob in EU (London)",
"beginRange": "0",
"endRange": "Inf",
"unit": "Character",
"pricePerUnit": {
"USD": "0.0000150000"
},
"appliesTo": []
}
},
"termAttributes": {}
}
}
}
}
}
The issue I run into is that the keys, which in this sample, are 7Y9ZZ3FXWPC86CZY, CQNY8UFVUNQQYYV4.JRTCKXETXF, and CQNY8UFVUNQQYYV4.JRTCKXETXF.6YS6EN2CT7 are a changing string that I cannot just type out as I am parsing the dictionary.
I have python code that works for the first level of these random keys -
with open('index.json') as json_file:
data = json.load(json_file)
json_keys=list(data['terms']['OnDemand'].keys())
#Get the region
for i in json_keys:
print((data['terms']['OnDemand'][i]))
However, this is tedious, as I would need to run the same code three times to get the other keys like 7Y9ZZ3FXWPC86CZY.JRTCKXETXF and 7Y9ZZ3FXWPC86CZY.JRTCKXETXF.6YS6EN2CT7, since the string changes with each JSON entry.
Is there a way that I can just tell python to automatically enter the next level of the JSON object, without having to parse all keys, save them, and then iterate through them? Using JQ in bash I can do this quite easily with jq -r '.terms[][][]'.
If you are really sure, that there is exactly one key-value pair on each level, you can try the following:
def descend(x, depth):
for i in range(depth):
x = next(iter(x.values()))
return x
You can use dict.values() to iterate over the values of a dict. You can also use next(iter(dict.values())) to get a first (only) element of a dict.
for demand in data['terms']['OnDemand'].values():
next_level = next(iter(demand.values()))
print(next_level)
If you expect other number of children than 1 in the second level, you can just nest the fors:
for demand in data['terms']['OnDemand'].values():
for sub_demand in demand.values()
print(sub_demand)
If you are insterested in the keys too, you can use dict.items() method to iterate over dict keys and values at the same time:
for demand_key, demand in data['terms']['OnDemand'].items():
for sub_demand_key, sub_demand in demand.items()
print(demand_key, sub_demand_key, sub_demand)

Using .values() with list of dictionaries?

I'm comparing json files between two different API endpoints to see which json records need an update, which need a create and what needs a delete. So, by comparing the two json files, I want to end up with three json files, one for each operation.
The json at both endpoints is structured like this (but they use different keys for same sets of values; different problem):
{
"records": [{
"id": "id-value-here",
"c": {
"d": "eee"
},
"f": {
"l": "last",
"f": "first"
},
"g": ["100", "89", "9831", "09112", "800"]
}, {
…
}]
}
So the json is represented as a list of dictionaries (with further nested lists and dictionaries).
If a given json endpoint (j1) id value ("id":) exists in the other endpoint json (j2), then that record should be added to j_update.
So far I have something like this, but I can see that .values() doesn't work because it's trying to operate on the list instead of on all the listed dictionaries(?):
j_update = {r for r in j1['records'] if r['id'] in
j2.values()}
This doesn't return an error, but it creates an empty set using test json files.
Seems like this should be simple, but tripping over the nesting I think of dictionaries in a list representing the json. Do I need to flatten j2, or is there a simpler dictionary method python has to achieve this?
====edit j1 and j2====
have same structure, use different keys; toy data
j1
{
"records": [{
"field_5": 2329309841,
"field_12": {
"email": "cmix#etest.com"
},
"field_20": {
"last": "Mixalona",
"first": "Clara"
},
"field_28": ["9002329309999", "9002329309112"],
"field_44": ["1002329309832"]
}, {
"field_5": 2329309831,
"field_12": {
"email": "mherbitz345#test.com"
},
"field_20": {
"last": "Herbitz",
"first": "Michael"
},
"field_28": ["9002329309831", "9002329309112", "8002329309999"],
"field_44": ["1002329309832"]
}, {
"field_5": 2329309855,
"field_12": {
"email": "nkatamaran#test.com"
},
"field_20": {
"first": "Noriss",
"last": "Katamaran"
},
"field_28": ["9002329309111", "8002329309112"],
"field_44": ["1002329309877"]
}]
}
j2
{
"records": [{
"id": 2329309831,
"email": {
"email": "mherbitz345#test.com"
},
"name_primary": {
"last": "Herbitz",
"first": "Michael"
},
"assign": ["8003329309831", "8007329309789"],
"hr_id": ["1002329309877"]
}, {
"id": 2329309884,
"email": {
"email": "yinleeshu#test.com"
},
"name_primary": {
"last": "Lee Shu",
"first": "Yin"
},
"assign": ["8002329309111", "9003329309831", "9002329309111", "8002329309999", "8002329309112"],
"hr_id": ["1002329309832"]
}, {
"id": 23293098338,
"email": {
"email": "amlouis#test.com"
},
"name_primary": {
"last": "Maxwell Louis",
"first": "Albert"
},
"assign": ["8002329309111", "8007329309789", "9003329309831", "8002329309999", "8002329309112"],
"hr_id": ["1002329309877"]
}]
}
If you read the json it will output a dict. You are looking for a particular key in the list of the values.
if 'records' in j2:
r = j2['records'][0].get('id', []) # defaults if id does not exist
It it prettier to do a recursive search but i dunno how you data is organized to quickly come up with a solution.
To give an idea for recursive search consider this example
def resursiveSearch(dictionary, target):
if target in dictionary:
return dictionary[target]
for key, value in dictionary.items():
if isinstance(value, dict):
target = resursiveSearch(value, target)
if target:
return target
a = {'test' : 'b', 'test1' : dict(x = dict(z = 3), y = 2)}
print(resursiveSearch(a, 'z'))
You tried:
j_update = {r for r in j1['records'] if r['id'] in j2.values()}
Aside from the r['id'/'field_5] problem, you have:
>>> list(j2.values())
[[{'id': 2329309831, ...}, ...]]
The id are buried inside a list and a dict, thus the test r['id'] in j2.values() always return False.
The basic solution is fairly simple.
First, create a set of j2 ids:
>>> present_in_j2 = set(record["id"] for record in j2["records"])
Then, rebuild the json structure of j1 but without the j1 field_5 that are not present in j2:
>>> {"records":[record for record in j1["records"] if record["field_5"] in present_in_j2]}
{'records': [{'field_5': 2329309831, 'field_12': {'email': 'mherbitz345#test.com'}, 'field_20': {'last': 'Herbitz', 'first': 'Michael'}, 'field_28': ['9002329309831', '9002329309112', '8002329309999'], 'field_44': ['1002329309832']}]}
It works, but it's not totally satisfying because of the weird keys of j1. Let's try to convert j1 to a more friendly format:
def map_keys(json_value, conversion_table):
"""Map the keys of a json value
This is a recursive DFS"""
def map_keys_aux(json_value):
"""Capture the conversion table"""
if isinstance(json_value, list):
return [map_keys_aux(v) for v in json_value]
elif isinstance(json_value, dict):
return {conversion_table.get(k, k):map_keys_aux(v) for k,v in json_value.items()}
else:
return json_value
return map_keys_aux(json_value)
The function focuses on dictionary keys: conversion_table.get(k, k) is conversion_table[k] if the key is present in the conversion table, or the key itself otherwise.
>>> j1toj2 = {"field_5":"id", "field_12":"email", "field_20":"name_primary", "field_28":"assign", "field_44":"hr_id"}
>>> mapped_j1 = map_keys(j1, j1toj2)
Now, the code is cleaner and the output may be more useful for a PUT:
>>> d1 = {record["id"]:record for record in mapped_j1["records"]}
>>> present_in_j2 = set(record["id"] for record in j2["records"])
>>> {"records":[record for record in mapped_j1["records"] if record["id"] in present_in_j2]}
{'records': [{'id': 2329309831, 'email': {'email': 'mherbitz345#test.com'}, 'name_primary': {'last': 'Herbitz', 'first': 'Michael'}, 'assign': ['9002329309831', '9002329309112', '8002329309999'], 'hr_id': ['1002329309832']}]}

python - remove a dictionary from a list if dictionary key equals a certain value

i want to know how to remove a specific dict from this list if user status equals "offline" and order type equals "buy" (iterating over it with for loop and modifying the list while iterating produces an exception because of the list pointer)
mylist = [
{
"user": {"status": "offline"},
"order_type": "buy"
},
{
"user": {"status": "online"},
"order_type": "sell"
}
]
You can re-create the list without undesired elements:
mylist = [key_values for key_values in mylist if key_values['user']['status'] != 'offline']
(*) do not name your variables using reserved keywords.
seq = [
{
"user": {"status": "offline"},
"order_type": "buy"
},
{ "user": {"status": "online"},
"order_type": "sell"
}
]
for _ in seq:
print _
if _['user']['status'] == 'offline':
seq.remove(_)
print seq
In case if you're looking for in place removal.
output:
[{'user': {'status': 'online'}, 'order_type': 'sell'}]

Adding key to values in json using Python

This is the structure of my JSON:
"docs": [
{
"key": [
null,
null,
"some_name",
"12345567",
"test_name"
],
"value": {
"lat": "29.538208354844658",
"long": "71.98762580927113"
}
},
I want to add the keys to the key list. This is what I want the output to look like:
"docs": [
{
"key": [
"key1":null,
"key2":null,
"key3":"some_name",
"key4":"12345567",
"key5":"test_name"
],
"value": {
"lat": "29.538208354844658",
"long": "71.98762580927113"
}
},
What's a good way to do it. I tried this but doesn't work:
for item in data['docs']:
item['test'] = data['docs'][3]['key'][0]
UPDATE 1
Based on the answer below, I have tweaked the code to this:
for number, item in enumerate(data['docs']):
# pprint (item)
# print item['key'][4]
newdict["key1"] = item['key'][0]
newdict["yek1"] = item['key'][1]
newdict["key2"] = item['key'][2]
newdict["yek2"] = item['key'][3]
newdict["key3"] = item['key'][4]
newdict["latitude"] = item['value']['lat']
newdict["longitude"] = item['value']['long']
This creates the JSON I am looking for (and I can eliminate the list I had previously). How does one make this JSON persist outside the for loop? Outside the loop, only the last value from the dictionary is added otherwise.
In your first block, key is a list, but in your second block it's a dict. You need to completely replace the key item.
newdict = {}
for number,item in enumerate(data['docs']['key']):
newdict['key%d' % (number+1)] = item
data['docs']['key'] = newdict

Categories

Resources