How to extract lists and modify them from different levels of nested dictionary - python

I want to extract all the lists and modify them from a nested dictionary which has multiple levels and the list can be a value in any of the levels.
For example:
test = {
'Type 1': {
'Type1_mainkey1': {
'Type1_key2': {
'Type1_key2_key1': [
'Type1_list1'
],
'Type1_key2_key2': [
'Type1_list2'
],
'Type1_key2_key2': [
'Type1_list3',
'Type1_list4'
]
}
}
},
'Type 2': {
'Type2_mainkey1': {
'Type2_key2': [
'Type2_list1',
'Type2_list2'
]},
'Type2_key3': {
'Type2_key3_key1': [
'Type2_list3',
'Type2_list4'
]
}
}
}
This is the kind of dictionary that might be present. I was wondering if there is a way of extracting the lists and updating the dictionary.
My function so far:
def find_list(data):
if not any([isinstance(data.get(k), dict) for k in data]):
return data
else:
for dkey in data:
if isinstance(data.get(dkey), dict):
return find_list(data.get(dkey))
else:
continue
And on running this:
out = find_list(test)
My output is:
{'Type1_key2_key1': ['Type1_list1'],
'Type1_key2_key2': ['Type1_list3', 'Type1_list4']}
Whereas, the expected output is all the list items and their keys (so that I can modify the list and update)

In my example below the only thing I am doing differently is collecting the results during each recursive step and adding to previous returns. I added some inline comments to hopefully better explain.
def find_list(data):
d = {} # initialize collection object to hold results
if not any([isinstance(data.get(k), dict) for k in data]):
return data
else:
for dkey in data:
if isinstance(data.get(dkey), dict):
# add results of each recursive call to the collection
d.update(find_list(data.get(dkey)))
return d # return the collection of results
Using your test dictionary with this example gives this output:
{
'Type1_key2_key1': ['Type1_list1'],
'Type1_key2_key2': ['Type1_list3', 'Type1_list4'],
'Type2_key2': ['Type2_list1', 'Type2_list2'],
'Type2_key3_key1': ['Type2_list3', 'Type2_list4']
}

Related

Querying a nested JSON file in Python without Indexing

I have the below Json file which I need to query to get the values of the keys inside 'validations' in a list
for example the column_values_not_null output will need to be this:
['lu_name', 'transaction_amount']
"validation_file_name": "ctm",
"connection_type": "s3",
"low_threshold": 500000,
"high_threshold": 1000000,
"frequency": "weekly",
"validations": [
{
"columns_to_match_ordered_list" :[
"lu_name",
"site_name",
"transaction_date_time",
"margin",
"transaction_currency_code",
"reversal_indicator_description",
"reversal_amount",
"original_amount"
]
},
{
"column_values_not_null":[
"lu_name",
"transaction_amount"
]
},
{
"column_values_not_duplicate": [
"lu_name",
"response_code_description"
]
}
]
I am able to do the below but I need to do this without using the index value
f = open('test.json')
json_content = json.load(f)
print(json_content['validations'][1]['column_values_not_null'])
Get a list by querying the validations key. The sum( ,[]) are used to flat the list (as required by the condition "without using the index value" if got it right), for details about it with pros and cons see doc.
data = #
def validations(data: dict, key_query: str) -> list:
for k, v in data.items():
if k == 'validations':
return sum(sum([list(d.values()) for d in v if key_query in d], []), [])
print(validations(data, query='column_values_not_null'))
# ['lu_name', 'transaction_amount']

Trying to convert text to nested dict in Python

I am trying to get a nested dict from a list of phrases.
My phrases for example are:
show version
show module
show module 0 det
show running-config
I am expecting a structure like this:
"show":{
"version":None,
"module":{
"0": {
"det"
}
},
"running-config":None
}
What I am trying is: split the phrases, from each array I am converting it to Dict.
for line in commandsOrdered:
value = line[-1]
line.pop(-1)
for key in list(reversed(line[:])):
value = {key: value}
sL.append(value)
And once I have a list of dicts, I am merging the dictionaries.
super_dict = {}
for d in sL:
for k, v in d.items():
super_dict.setdefault(k, []).append(v)
But I am getting this:
{
"show": [
"module",
{
"module": {
"0": "det"
}
},
"running-config",
"version"
],
"0": [
"det"
],
"module": [
{
"0": "det"
}
]
}
The max depth I have is 9 words in a phrase.
Any idea how to solve this?
Thanks
Something like this is fairly straightforward:
commandsOrdered = [
'show version',
'show module',
'show module 0 det',
'show running-config'
]
result = {}
for command in commandsOrdered:
parts = command.split()
d = result
for key in parts[:-1]:
if key not in d or not d[key]:
d[key] = {}
d = d[key]
d[parts[-1]] = None
print(result)
Output:
{'show': {'version': None, 'module': {'0': {'det': None}}, 'running-config': None}}
Not using defaultdict to meet the None requirement. You could easily write this recursively as well though, given the limited depth. That would make for simpler code, but not a faster solution per se.

How do I extract a list item from nested json in Python?

I have a json object and I'm trying to extract a couple of values from a nested list. Then print them in markup. I'm getting and error - AttributeError: 'list' object has no attribute 'get'
I understand that it's a list and I can't preform a get. I've been searching for the proper method for a few hours now and I'm running out of steam. I'm able to get the Event, but not Value1 and Value2.
This is the json object
{
"resource": {
"data": {
"event": "qwertyuiop",
"eventVersion": "1.05",
"parameters": {
"name": "sometext",
"othername": [
""
],
"thing": {
"something": {
"blah": "whatever"
},
"abc": "123",
"def": {
"xzy": "value"
}
},
"something": [
"else"
]
},
"whatineed": [{
"value1": "text.i.need",
"value2": "text.i.need.also"
}]
}
}
}
And this is my function
def parse_json(json_data: dict) -> Info:
some_data = json_data.get('resource', {})
specific_data = some_data.get('data', {})
whatineed_data = specific_data.get('whatineed', {})
formatted_json = json.dumps(json_data, indent=2)
description = f'''
h3. Details
*Event:* {some_data.get('event')}
*Value1:* {whatineed_data('value1')}
*Value2:* {whatineed_data('value2')}
'''
From the data structure, whatineed is a list with a single item, which in turn is a dictionary. So, one way to access it would be:
whatineed_list = specific_data.get('whatineed', [])
whatineed_dict = whatineed_list[0]
At this point you can do:
value1 = whatineed_dict.get('value1')
value2 = whatineed_dict.get('value2')
You can change your function to the following:
def parse_json(json_data: dict) -> Info:
some_data = json_data.get('resource')
specific_data = some_data.get('data', {})
whatineed_data = specific_data.get('whatineed', {})
formatted_json = json.dumps(json_data, indent=2)
description = '''
h3. Details
*Event:* {}
*Value1:* {}
*Value2:* {}
'''.format(some_data.get('data').get('event'),whatineed_data[0]['value1'], whatineed_data[0]['value2'])
Since whatineed_data is a list, you need to index the element first
Python handles json as strings unless they are coming directly from a file. This could be the source for some of your problems. Also this article might help.
Assuming that "whatineed" attribute is really a list, and it's elements are dicts, you can't call whatineed.get asking for Value1 or Value2 as if they are attributes, because it is a list and it don't have attributes.
So, you have two options:
If whatineed list has a single element ever, you can access this element directly and than access the element attributes:
element = whatineed[0]
v1 = element.get('value1', {})
v2 = element.get('value2', {})
Or, if whatineed list can have more items, so, you will need to iterate over this list and access those elements:
for element in whatineed:
v1 = element.get('value1', {})
v2 = element.get('value2', {})
## Do something with values

golang defining dict like python with and appending value to list in dict

I am new to go and trying to implement python like nested structure as below, I am not able to define the empty dict/map in golang that can have list of specific struct/classobj and while iterating through the data I am not able to append items in map/dict ... I will really appreciate any help on this ... Thanks
items = [
("item1", someObj1),
("item2", someObj2),
("item3", someObj3),
("item3", someObj5),
("item1", someObj4),
]
rectors = {}
for item, obj in items:
try:
rectors[item].append(obj)
except KeyError:
rectors[item] = [obj]
print rectors
# OUTPUT: {'item2': [someObj2], 'item3': [someObj3, someObj5], 'item1': [someObj1, someObj4]}
Its not quite as clean .. but this does roughly what you want and should get you started on the right path:
type someObj struct {
}
func main() {
items := map[string][]someObj{
"item1": []someObj{someObj{}},
"item2": []someObj{someObj{}},
"item3": []someObj{someObj{}},
}
items["item1"] = append(items["item1"], someObj{})
rectors := make(map[string][]someObj)
for key, val := range items {
if obj, exists := rectors[key]; exists {
rectors[key] = append(obj, val...)
} else {
rectors[key] = val
}
}
fmt.Printf("%v", rectors)
}
Output:
map[item3:[{}] item1:[{} {}] item2:[{}]]
The main difference being .. you can't initialize the map and alter an item with a key that already exists (as you appear to be doing in your example with item1 being appended during initialization). So that becomes an extra step after the initialization of the map. You could always just do:
"item1": []someObj{someObj{}, someObj{}},
.. but that didn't seem to be the same as what you were doing.
See it on the Go playground

Logic for building converter using python dictionary values

I have such slice of loaded json tp python dictionary (size_dict):
{
"sizeOptionName":"XS",
"sizeOptionId":"1528",
"sortOrderNumber":"7017"
},
{
"sizeOptionName":"S",
"sizeOptionId":"1529",
"sortOrderNumber":"7047"
},
{
"sizeOptionName":"M",
"sizeOptionId":"1530",
"sortOrderNumber":"7095"
}
and I have products with size Id (dictionary_prod):
{
"catalogItemId":"7627712",
"catalogItemTypeId":"3",
"regularPrice":"0.0",
"sizeDimension1Id":"1528",
"sizeDimension2Id":"0",
}
I need to make such as output for any product:
result_dict = {'variant':
[{"catalogItemId":"7627712", ...some other info...,
'sizeName': 'XS', 'sizeId': '1525'}}]}
so I need to convert size ID and add it to new result object
What is the best pythonic way to do this?
I dont know how to get right data from size_dict
if int(dictionary_prod['sizeDimension1Id']) > o:
(result_dict['variant']).append('sizeName': size_dict???)
As Tommy mentioned, this is best facilitated by mapping the size id's to their respective dictionaries.
size_dict = \
[
{
"sizeOptionName":"XS",
"sizeOptionId":"1528",
"sortOrderNumber":"7017"
},
{
"sizeOptionName":"S",
"sizeOptionId":"1529",
"sortOrderNumber":"7047"
},
{
"sizeOptionName":"M",
"sizeOptionId":"1530",
"sortOrderNumber":"7095"
}
]
size_id_map = {size["sizeOptionId"] : size for size in size_dict}
production_dict = \
[
{
"catalogItemId":"7627712",
"catalogItemTypeId":"3",
"regularPrice":"0.0",
"sizeDimension1Id":"1528",
"sizeDimension2Id":"0",
}
]
def make_variant(idict):
odict = idict.copy()
size_id = odict.pop("sizeDimension1Id")
odict.pop("sizeDimension2Id")
odict["sizeName"] = size_id_map[size_id]["sizeOptionName"]
odict["sizeId"] = size_id
return odict
result_dict = \
{
"variant" : [make_variant(product) for product in production_dict]
}
print(result_dict)
Your question is a little confusing but it looks like you have a list (size_dict) of dictionaries that contain some infroamtion and you want to do a lookup to find a particular element in the list that contains the SizeOptionName you are interested in so that you can read off the SizeOptionID.
So first you could organsie your size_dict as a dictionary rather than a list - i.e.
sizeDict = {"XS":{
"sizeOptionName":"XS",
"sizeOptionId":"1528",
"sortOrderNumber":"7017"
}, "S": {
"sizeOptionName":"S",
"sizeOptionId":"1529",
"sortOrderNumber":"7047"
}, ...
You could then read off the SizeOptionID you need by doing:
sizeDict[sizeNameYouAreLookingFor][SizeOptionID]
Alternative you could keep your current structure and just search the list of dictionaries that is size_dict.
So:
for elem in size_dict:
if elem.SizeOptionID == sizeYouAreLookingFor:
OptionID = elem.SizeOptionId
Or perhaps you are asking something else?

Categories