How to compare python dictionaries based on specific key - python

I have data files of json and xml which return me account details of customer. They both have almost the same data in them and i have to verify it. It may have a single account or multiple. I have made the a dictionary of selected keys which i need to verify. I need help in:
1) Storing the multiple dictionaries somewhere so i can compare it.
2) And a way to compare them.
I am providing a sample data file which contain multiple accounts.
rest = {
"ReqType": "CRI",
"ReqUID": "1234567",
"ResultCode": "00",
"Message": "Success",
"Records": 2,
"OutData": [
{
"CNIC": "123456789",
"PSTS": "P",
"CUSTNO": "CHO7SM",
"Accounts": {
"NoAccounts": "1",
"AccountList": [
{
"ACC#": "17327901207",
"TITLE": "John",
"TYPE": "C",
"STYPE": "C4",
"STPDESC": "ACCOUNT CURRENT",
"REL": "N",
"LBAL": "2500000",
"ABAL": "2500000",
"DECEASED": "N",
"BLOCKED": "N",
"INACTIVE": "N",
"CLOSED": "N"
}
]
}
},
{
"CNIC": "123456789",
"PSTS": "S",
"CUSTNO": "CDG1R8",
"Accounts": {
"NoAccounts": "1",
"AccountList": [
{
"ACC#": "17327900081",
"TITLE": "John",
"TYPE": "C",
"STYPE": "C4",
"STPDESC": "ACCOUNT CURRENT",
"REL": "N",
"LBAL": "3486039",
"ABAL": "3486039",
"DECEASED": "N",
"BLOCKED": "N",
"INACTIVE": "N",
"CLOSED": "N"
}
]
}
}
]
}
xml = <?xml version="1.0" encoding="UTF-8"?>
<FCDB_RES_ENV>
<FCDB_HEADER>
<SOURCE>FCAT</SOURCE>
<SERVICE>CustomerAccountsDetails</SERVICE>
<OPERATION>CustomerAccountsDetails</OPERATION>
<SOURCE_USERID>FCAT</SOURCE_USERID>
<DESTINATION>FCDB</DESTINATION>
<COUNTRYCODE>T001</COUNTRYCODE>
<USERTYPE>ENS</USERTYPE>
<LANGID>eng</LANGID>
<CHANNELID>01</CHANNELID>
</FCDB_HEADER>
<FCDB_BODY>
<CUSTACCOUNT>
<CUSTNO>
<CUSTNO>123456789</CUSTNO>
<TYPECUST>C</TYPECUST>
<NAMCUST>John</NAMCUST>
<ADDRESS>
<ADDRESS1>ABC.</ADDRESS1>
</ADDRESS>
</CUSTNO>
<ACCOUNT>
<CUSTNO>123456789</CUSTNO>
<ACCNO>17327901207</ACCNO>
<ACCOUNTTITLE>John</ACCOUNTTITLE>
<ACCOUNTTYPEDETAIL>C4</ACCOUNTTYPEDETAIL>
<BALANCE>25000.00</BALANCE>
<ACCTTYPE>C</ACCTTYPE>
<ACCPRD>AAAA</ACCPRD>
<ACCPRDDESC>ACCOUNT CURRENT</ACCPRDDESC>
<ACCCCY>PKR</ACCCCY>
<STATUS>A</STATUS>
<RELATION>J</RELATION>
<BAL_AVAIL>25000.00</BAL_AVAIL>
<HASCHEQUE>true</HASCHEQUE>
<HASOVERDRAFT>N</HASOVERDRAFT>
<UNCLEARFUND>0.00</UNCLEARFUND>
</ACCOUNT>
<ACCOUNT>
<CUSTNO>123456789</CUSTNO>
<ACCNO>17327900081</ACCNO>
<ACCOUNTTITLE>John</ACCOUNTTITLE>
<ACCOUNTTYPEDETAIL>C4</ACCOUNTTYPEDETAIL>
<BALANCE>34860.39</BALANCE>
<ACCTTYPE>C</ACCTTYPE>
<ACCPRD>AAAA</ACCPRD>
<ACCPRDDESC>ACCOUNT CURRENT</ACCPRDDESC>
<ACCCCY>PKR</ACCCCY>
<STATUS>A</STATUS>
<RELATION>J</RELATION>
<BAL_AVAIL>34860.39</BAL_AVAIL>
<HASCHEQUE>true</HASCHEQUE>
<HASOVERDRAFT>N</HASOVERDRAFT>
<UNCLEARFUND>0.00</UNCLEARFUND>
</ACCOUNT>
<ACCOUNT>
<CUSTNO>123456789</CUSTNO>
<ACCNO>17327900940</ACCNO>
<ACCOUNTTITLE>Adam</ACCOUNTTITLE>
<ACCOUNTTYPEDETAIL>C4</ACCOUNTTYPEDETAIL>
<BALANCE>2004976.00</BALANCE>
<ACCTTYPE>C</ACCTTYPE>
<ACCPRD>AAAA</ACCPRD>
<ACCPRDDESC>ACCOUNT CURRENT</ACCPRDDESC>
<ACCCCY>PKR</ACCCCY>
<STATUS>A</STATUS>
<RELATION>J</RELATION>
<BAL_AVAIL>2004976.00</BAL_AVAIL>
<HASCHEQUE>true</HASCHEQUE>
<HASOVERDRAFT>N</HASOVERDRAFT>
<UNCLEARFUND>0.00</UNCLEARFUND>
</ACCOUNT>
</CUSTACCOUNT>
<FCDB_ERROR_RESP>
<ERROR>
<ECODE>00</ECODE>
<EDESC>Your transaction has been processed successfully.</EDESC>
</ERROR>
</FCDB_ERROR_RESP>
</FCDB_BODY>
</FCDB_RES_ENV>
I have converted the soap response into a dictionary to get the items easily.
import json
import xmltodict
from collections import OrderedDict
rest_file = json.loads(rest.read())
doc = xmltodict.parse(xml.read())
input_dict = OrderedDict(doc)
xml_file = json.loads(json.dumps(input_dict))
a = xml['FCDB_RES_ENV']['FCDB_BODY']['CUSTACCOUNT']
for i in a.__getitem__('ACCOUNT'):
xml_dict = {key: a[key] for key in a if key in ['ACCNO', 'ACCOUNTTITLE', 'ACCOUNTTYPEDETAIL', 'ACCPRDDESC']}
print(soap_dict)
print("--------------------")
for item in rest.get('OutData'):
b = (item.get('Accounts')['AccountList'])
json_file_account = b.pop()
rest_dict = {key: json_file_account[key] for key in json_file_account if key in
['ACC#', 'TITLE', 'STYPE', 'STPDESC']}
print(rest_dict)
The Output of above script is:
{'ACCNO': '17327901207', 'ACCOUNTTITLE': 'John', 'ACCOUNTTYPEDETAIL': 'C4', 'ACCPRDDESC': 'ACCOUNT CURRENT'}
{'ACCNO': '17327900081', 'ACCOUNTTITLE': 'John', 'ACCOUNTTYPEDETAIL': 'C4', 'ACCPRDDESC': 'ACCOUNT CURRENT'}
{'ACCNO': '17327900940', 'ACCOUNTTITLE': 'Adam', 'ACCOUNTTYPEDETAIL': 'C4', 'ACCPRDDESC': 'ACCOUNT CURRENT'}
--------------------
{'ACC#': '17327901207', 'TITLE': 'John', 'STYPE': 'C4', 'STPDESC': 'ACCOUNT CURRENT'}
{'ACC#': '17327900081', 'TITLE': 'John', 'STYPE': 'C4', 'STPDESC': 'ACCOUNT CURRENT'}
For Comparison, I need to iterate the first dictionary of xml into rest and see if AccNo matches then compare all values. Any help would be appreciated. Thanks

First You need to append all dict into a list and then iterate over it and match the value of accounts.
Below is the modified code.
import json
import xmltodict
from collections import OrderedDict
rest_file = json.loads(rest.read())
doc = xmltodict.parse(xml.read())
input_dict = OrderedDict(doc)
xml_file = json.loads(json.dumps(input_dict))
soap_dict_list = []
a = xml['FCDB_RES_ENV']['FCDB_BODY']['CUSTACCOUNT']
for i in a.__getitem__('ACCOUNT'):
xml_dict = {key: a[key] for key in a if key in ['ACCNO', 'ACCOUNTTITLE', 'ACCOUNTTYPEDETAIL', 'ACCPRDDESC']}
print(soap_dict)
soap_dict_list.append(soap_dict)
print(soap_dict_list)
print("--------------------")
rest_dict_list = []
for item in rest.get('OutData'):
b = (item.get('Accounts')['AccountList'])
json_file_account = b.pop()
rest_dict = {key: json_file_account[key] for key in json_file_account if key in
['ACC#', 'TITLE', 'STYPE', 'STPDESC']}
print(rest_dict)
rest_dict_list.append(rest_dict)
print(rest_dict_list)
# Now iterate over list
for info1 in rest_dict_list:
for info2 in soap_dict_list:
if info1['ACC#'] == info2['ACCNO']:
print("Account number Match found")
if info1['TITLE'] == info2['ACCOUNTTITLE']:
print("ACCOUNTTITLE and TITLE matched")
# and so on you can match rest of values

Ali Khan,
1.) I would suggest grouping them by using keys alone since the keys seem to vary into a list groups.
2.) After grouping is completed try using pandas Dataframe package to compare.
Here is my code below to compare all those values.
import pandas as pd
df_struct = list()
df_struct.append({'ACCNO': '17327901207', 'ACCOUNTTITLE': 'John', 'ACCOUNTTYPEDETAIL': 'C4', 'ACCPRDDESC': 'ACCOUNT CURRENT'})
df_struct.append({'ACCNO': '17327900081', 'ACCOUNTTITLE': 'John', 'ACCOUNTTYPEDETAIL': 'C4', 'ACCPRDDESC': 'ACCOUNT CURRENT'})
df_struct.append({'ACCNO': '17327900940', 'ACCOUNTTITLE': 'Adam', 'ACCOUNTTYPEDETAIL': 'C4', 'ACCPRDDESC': 'ACCOUNT CURRENT'})
df = pd.DataFrame(df_struct)
print(df[df['ACCNO'].duplicated()])

Related

How do I converted my textfile to a nested json in python

I have a text file which I want to convert to a nested json structure. The text file is :
Report_for Reconciliation
Execution_of application_1673496470638_0001
Spark_version 2.4.7-amzn-0
Java_version 1.8.0_352 (Amazon.com Inc.)
Start_time 2023-01-12 09:45:13.360000
Spark Properties:
Job_ID 0
Submission_time 2023-01-12 09:47:20.148000
Run_time 73957ms
Result JobSucceeded
Number_of_stages 1
Stage_ID 0
Number_of_tasks 16907
Number_of_executed_tasks 16907
Completion_time 73207ms
Stage_executed parquet at RawDataPublisher.scala:53
Job_ID 1
Submission_time 2023-01-12 09:48:34.177000
Run_time 11525ms
Result JobSucceeded
Number_of_stages 2
Stage_ID 1
Number_of_tasks 16907
Number_of_executed_tasks 0
Completion_time 0ms
Stage_executed parquet at RawDataPublisher.scala:53
Stage_ID 2
Number_of_tasks 300
Number_of_executed_tasks 300
Completion_time 11520ms
Stage_executed parquet at RawDataPublisher.scala:53
Job_ID 2
Submission_time 2023-01-12 09:48:46.908000
Run_time 218358ms
Result JobSucceeded
Number_of_stages 1
Stage_ID 3
Number_of_tasks 1135
Number_of_executed_tasks 1135
Completion_time 218299ms
Stage_executed parquet at RawDataPublisher.scala:53
I want the output to be :
{
"Report_for": "Reconciliation",
"Execution_of": "application_1673496470638_0001",
"Spark_version": "2.4.7-amzn-0",
"Java_version": "1.8.0_352 (Amazon.com Inc.)",
"Start_time": "2023-01-12 09:45:13.360000",
"Job_ID 0": {
"Submission_time": "2023-01-12 09:47:20.148000",
"Run_time": "73957ms",
"Result": "JobSucceeded",
"Number_of_stages": "1",
"Stage_ID 0”: {
"Number_of_tasks": "16907",
"Number_of_executed_tasks": "16907",
"Completion_time": "73207ms",
"Stage_executed": "parquet at RawDataPublisher.scala:53"
"Stage": "parquet at RawDataPublisher.scala:53",
},
},
}
I tried defaultdict method but it was generating a json with values as list which was not acceptable to make a table on it. Here's what I did:
import json
from collections import defaultdict
INPUT = 'demofile.txt'
dict1 = defaultdict(list)
def convert():
with open(INPUT) as f:
for line in f:
command, description = line.strip().split(None, 1)
dict1[command].append(description.strip())
OUTPUT = open("demo1file.json", "w")
json.dump(dict1, OUTPUT, indent = 4, sort_keys = False)
and was getting this:
"Report_for": [ "Reconciliation" ],
"Execution_of": [ "application_1673496470638_0001" ],
"Spark_version": [ "2.4.7-amzn-0" ],
"Java_version": [ "1.8.0_352 (Amazon.com Inc.)" ],
"Start_time": [ "2023-01-12 09:45:13.360000" ],
"Job_ID": [
"0",
"1",
"2", ....
]]]
I just want to convert my text to the above json format so that I can build a table on top of it.
There's no way, python or one of it's libraries can figure out your nesting requirements, if a flat text is being given as an input. How should it know Stages are inside Jobs...for example.
You will have to programmatically tell your application how it works.
I hacked an example which should work, you can go from there (assuming input_str is what you posted as your file content):
# define your nesting structure
nesting = {'Job_ID': {'Stage_ID': {}}}
upper_nestings = []
upper_nesting_keys = []
# your resulting dictionary
result_dict = {}
# your "working" dictionaries
current_nesting = nesting
working_dict = result_dict
# parse each line of the input string
for line_str in input_str.split('\n'):
# key is the first word, value are all consecutive words
line = line_str.split(' ')
# if key is in nesting, create new sub-dict, all consecutive entries are part of the sub-dict
if line[0] in current_nesting.keys():
current_nesting = current_nesting[line[0]]
upper_nestings.append(line[0])
upper_nesting_keys.append(line[1])
working_dict[line_str] = {}
working_dict = working_dict[line_str]
else:
# if a new "parallel" or "upper" nesting is detected, reset your nesting structure
if line[0] in upper_nestings:
nests = upper_nestings[:upper_nestings.index(line[0])]
keys = upper_nesting_keys[:upper_nestings.index(line[0])]
working_dict = result_dict
for nest in nests:
working_dict = working_dict[' '.join([nest, keys[nests.index(nest)]])]
upper_nestings = upper_nestings[:upper_nestings.index(line[0])+1]
upper_nesting_keys = upper_nesting_keys[:upper_nestings.index(line[0])]
upper_nesting_keys.append(line[1])
current_nesting = nesting
for nest in upper_nestings:
current_nesting = current_nesting[nest]
working_dict[line_str] = {}
working_dict = working_dict[line_str]
continue
working_dict[line[0]] = ' '.join(line[1:])
print(result_dict)
Results in:
{
'Report_for': 'Reconciliation',
'Execution_of': 'application_1673496470638_0001',
'Spark_version': '2.4.7-amzn-0',
'Java_version': '1.8.0_352 (Amazon.com Inc.)',
'Start_time': '2023-01-12 09:45:13.360000',
'Spark': 'Properties: ',
'Job_ID 0': {
'Submission_time': '2023-01-12 09:47:20.148000',
'Run_time': '73957ms',
'Result': 'JobSucceeded',
'Number_of_stages': '1',
'Stage_ID 0': {
'Number_of_tasks': '16907',
'Number_of_executed_tasks': '16907',
'Completion_time': '73207ms',
'Stage_executed': 'parquet at RawDataPublisher.scala:53'
}
},
'Job_ID 1': {
'Submission_time': '2023-01-12 09:48:34.177000',
'Run_time': '11525ms',
'Result': 'JobSucceeded',
'Number_of_stages': '2',
'Stage_ID 1': {
'Number_of_tasks': '16907',
'Number_of_executed_tasks': '0',
'Completion_time': '0ms',
'Stage_executed': 'parquet at RawDataPublisher.scala:53'
},
'Stage_ID 2': {
'Number_of_tasks': '300',
'Number_of_executed_tasks': '300',
'Completion_time': '11520ms',
'Stage_executed': 'parquet at RawDataPublisher.scala:53'
}
},
'Job_ID 2': {
'Submission_time':
'2023-01-12 09:48:46.908000',
'Run_time': '218358ms',
'Result': 'JobSucceeded',
'Number_of_stages': '1',
'Stage_ID 3': {
'Number_of_tasks': '1135',
'Number_of_executed_tasks': '1135',
'Completion_time': '218299ms',
'Stage_executed': 'parquet at RawDataPublisher.scala:53'
}
}
}
and should pretty much be generically usable for all kinds of nesting definitions from a flat input. Let me know if it works for you!

How to dynamically generate key and assign values to a nested dictionary in python

I have a list of dictionaries as input :
[{
Acc: "ABC IN."
CFC: "XC"
CC: "1001"
SC: "DER"
Config Path: "..//"
File Path: "..//"
}]
I wanted to convert it into a template nested dictionary the only catch being the key of the nested dictionary is also derived from the above dictionary itself
Desired output
{'XC': {'1001': {'DER': {'Config Path': '..//' ,'File Path' : "..//" }}}}
The input can be multiple and whenever a new CFC , CC or SC arrives a new key is generated on the same level as that of the previous .
I tried dynamically generating key but it was showing key not found error
main_dict = {}
for item in main_dict_list:
main_dict[item['CFC']][item['CC']][item['SC']]['Config Path']=item['Config Path']
main_dict[item['CFC']][item['CC']][item['SC']]['File Path']=item['File Path']
I also tried to follow hierarchy to input key-value from inside the dictionary
main_dict = {}
for item in main_dict_list:
temp={}
temp['model_config_path']=item['Config Path']
temp['model_config_path']=item['File Path']
temp1 = {}
temp1[item['SC']] = temp
temp2 ={}
temp2[item['CC']] =temp1
main_dict[item['CFC']] =temp2
it also doesn't seem to work properly.
I am not able to think about any other solution
You have to create each level.
main_dict = {}
for item in main_dict_list:
main_dict[item['CFC']] = {item['CC']: {item['SC']: {'Config Path': item['Config Path'], 'File Path': item['File Path']}}}
You can use setdefault to auto-merge common keys:
main_dict_list = [
{ 'Acc': "ABC IN.",
'CFC': "XC",
'CC': "1001",
'SC': "DER",
'Config Path': "..//",
'File Path': "..//"
},
{ 'Acc': "ABC IN.",
'CFC': "XC",
'CC': "1002",
'SC': "DER",
'Config Path': "..//c",
'File Path': "..//f"
},
]
main_dict = dict()
for d in main_dict_list:
content = {k:d[k] for k in ("Config Path","File Path") }
main_dict.setdefault(d["CFC"],dict()) \
.setdefault(d["CC"],dict()) \
.setdefault(d["SC"],content)
print(main_dict)
{'XC': {'1001': {'DER': {'Config Path': '..//', 'File Path': '..//'}},
'1002': {'DER': {'Config Path': '..//c', 'File Path': '..//f'}}}}

How to transform JSON SList to pandas dataframe?

a = ['{"type": "book",',
'"title": "sometitle",',
'"author": [{"name": "somename"}],',
'"year": "2000",',
'"identifier": [{"type": "ISBN", "id": "1234567890"}],',
'"publisher": "somepublisher"}', '',
'{"type": "book",', '
'"title": "sometitle2",',
'"author": [{"name": "somename2"}],',
'"year": "2001",',
'"identifier": [{"type": "ISBN", "id": "1234567890"}],',
'"publisher": "somepublisher"}', '']
I have this convoluted SList and I would like to ultimately get it into a tidy pandas dataframe.
I have tried a number of things, for example:
i = iter(a)
b = dict(zip(i, i))
Unfortunately, this creates a dictionary that looks even worse:
{'{"type": "book",':
...
Where I had an SList of dictionaries, I now have a dictionary of dictionaries.
I also tried
pd.json_normalize(a)
but this throws an error message AttributeError: 'str' object has no attribute 'values'
I also tried
r = json.dumps(a.l)
loaded_r = json.loads(r)
print(loaded_r)
but this yields a list
['{"type": "book",',
...
Again, in the end I'd like to have a pandas dataframe like this
type title author year ...
book sometitle somename 2000 ...
book sometitle2 somename2 2001
Obviously, I haven't really gotten to the point where I can feed the data to a pandas function. Everytime I did that, the functions screamed at me...
a = ['{"type": "book",',
'"title": "sometitle",',
'"author": [{"name": "somename"}],',
'"year": "2000",',
'"identifier": [{"type": "ISBN", "id": "1234567890"}],',
'"publisher": "somepublisher"}', '',
'{"type": "book",',
'"title": "sometitle2",',
'"author": [{"name": "somename2"}],',
'"year": "2001",',
'"identifier": [{"type": "ISBN", "id": "1234567890"}],',
'"publisher": "somepublisher"}', '']
b = "[%s]" % ''.join([',' if i == '' else i for i in a ]).strip(',')
data = json.loads(b)
df = pd.DataFrame(data)
print(df)
type title author year \
0 book sometitle [{'name': 'somename'}] 2000
1 book sometitle2 [{'name': 'somename2'}] 2001
identifier publisher
0 [{'type': 'ISBN', 'id': '1234567890'}] somepublisher
1 [{'type': 'ISBN', 'id': '1234567890'}] somepublisher

Group data inside list of dictionary python

I have a list of dictionaries like this
data = [
{"_id": {"cohort_name": "09-01-2010", "segment_name": "LTV90-Prime", "driver_name": "ADB"}, "cohort_data": [
{"calculated": [],
"original": [{"1": 225.2699758337715}, {"2": 106.05173118059133}, {"3": 547.2908664469512},
{"4": 573.1083659247656}]}]},
{"_id": {"cohort_name": "11-01-2010", "segment_name": "LTV90-Prime", "driver_name": "Unit Loss Rate"},
"cohort_data": [{"calculated": [], "original": [{"1": 0.002687180620372531}, {"2": 0.001468127113897437}]}]},
{"_id": {"cohort_name": "11-01-2010", "segment_name": "LTV90-Prime", "driver_name": "Unit Loss Rate"},
"cohort_data": [{"calculated": [], "original": [{"10": 0.002687180620372531}, {"1": 0.002687180620372531},
{"2": 0.001468127113897437}]}]}
]
I am trying to group data based upon the driver_name and segment_name and push all cohort_name and cohort_data inside the internal dictionary.
The expected output is as follows
[{'driver_name': 'Unit Loss Rate',
'segment_name': 'LTV90-Prime',
'cohort_data': {
'5-01-2010': [{'1': 0.002687180620372531}, {'2': 0.001468127113897437}, {'10': 0.002687180620372531}],
'11-01-2010': [{'1': 0.002687180620372531}, {'2': 0.001468127113897437}]
}},
{'driver_name': 'ADB',
'segment_name': 'LTV90-Prime',
'cohort_data': {
"09-01-2010": [{'1': 225.2699758337715}, {'2': 106.05173118059133}, {'3': 547.2908664469512},
{'4': 573.1083659247656}]
}}
]
This is what I have done so far. I am stuck in pushing the cohort_name and cohort_data in the internal dictionary.
def get_data_list(d):
final_data = None
for i in d:
calculated = i['calculated']
original = i['original']
if original:
final_data = original
elif calculated:
final_data = calculated
return final_data
dd = defaultdict(dict)
for i in data:
df = {}
id_ = i['_id']
cohort_name_final, segment_name_final, driver_name_final = id_['cohort_name'], \
id_['segment_name'], \
id_['driver_name']
cohort_data_final = i['cohort_data']
if segment_name_final not in df and segment_name_final not in df:
df['segment_name'] = segment_name_final
df['driver_name'] = driver_name_final
df['cohort_data'] = get_data_list(cohort_data_final)
elif segment_name_final in df and segment_name_final in df:
df['cohort_data'].append(get_data_list(cohort_data_final))
# df['cohort_data'].append({cohort_name_final: get_data_list(cohort_data_final)})
I am using Python 3.4.3. The data shown here is an subset of an original dataset which is queried from the MongoDB database.
Please help.

How can I change the value of a node in a python dictionary by following a list of keys?

I have a bit of a complex question that I can't seem to get to the bottom of. I have a list of keys corresponding to a position in a Python dictionary. I would like to be able to dynamically change the value at the position (found by the keys in the list).
For example:
listOfKeys = ['car', 'ford', 'mustang']
I also have a dictionary:
DictOfVehiclePrices = {'car':
{'ford':
{'mustang': 'expensive',
'other': 'cheap'},
'toyota':
{'big': 'moderate',
'small': 'cheap'}
},
'truck':
{'big': 'expensive',
'small': 'moderate'}
}
Via my list, how could I dynamically change the value of DictOfVehiclePrices['car']['ford']['mustang']?
In my actual problem, I need to follow the list of keys through the dictionary and change the value at the end position. How can this be done dynamically (with loops, etc.)?
Thank you for your help! :)
Use reduce and operator.getitem:
>>> from operator import getitem
>>> lis = ['car', 'ford', 'mustang']
Update value:
>>> reduce(getitem, lis[:-1], DictOfVehiclePrices)[lis[-1]] = 'cheap'
Fetch value:
>>> reduce(getitem, lis, DictOfVehiclePrices)
'cheap'
Note that in Python 3 reduce has been moved to functools module.
A very simple approach would be:
DictOfVehiclePrices[listOfKeys[0]][listOfKeys[1]][listOfKeys[2]] = 'new value'
print reduce(lambda x, y: x[y], listOfKeys, dictOfVehiclePrices)
Output
expensive
In order to change the values,
result = dictOfVehiclePrices
for key in listOfKeys[:-1]:
result = result[key]
result[listOfKeys[-1]] = "cheap"
print dictOfVehiclePrices
Output
{'car': {'toyota': {'small': 'cheap', 'big': 'moderate'},
'ford': {'mustang': 'cheap', 'other': 'cheap'}},
'truck': {'small': 'moderate', 'big': 'expensive'}}
You have a great solution here by #Joel Cornett.
based on Joel method you can use it like this:
def set_value(dict_nested, address_list):
cur = dict_nested
for path_item in address_list[:-2]:
try:
cur = cur[path_item]
except KeyError:
cur = cur[path_item] = {}
cur[address_list[-2]] = address_list[-1]
DictOfVehiclePrices = {'car':
{'ford':
{'mustang': 'expensive',
'other': 'cheap'},
'toyota':
{'big': 'moderate',
'small': 'cheap'}
},
'truck':
{'big': 'expensive',
'small': 'moderate'}
}
set_value(DictOfVehiclePrices,['car', 'ford', 'mustang', 'a'])
print DictOfVehiclePrices
STDOUT:
{'car': {'toyota': {'small': 'cheap', 'big': 'moderate'}, 'ford':
{'mustang': 'a', 'other': 'cheap'}}, 'truck': {'small': 'moderate',
'big': 'expensive'}}
def update_dict(parent, data, value):
'''
To update the value in the data if the data
is a nested dictionary
:param parent: list of parents
:param data: data dict in which value to be updated
:param value: Value to be updated in data dict
:return:
'''
if parent:
if isinstance(data[parent[0]], dict):
update_dict(parent[1:], data[parent[0]], value)
else:
data[parent[0]] = value
parent = ["test", "address", "area", "street", "locality", "country"]
data = {
"first_name": "ttcLoReSaa",
"test": {
"address": {
"area": {
"street": {
"locality": {
"country": "india"
}
}
}
}
}
}
update_dict(parent, data, "IN")
Here is a recursive function to update a nested dict based on a list of keys:
1.Trigger the update dict function with the required params
2.The function will iterate the list of keys, and retrieves the value from the dict.
3.If the retrieved value is dict, it pops the key from the list and also it updates the dict with the value of the key.
4.Sends the updated dict and list of keys to the same function recursively.
5.When the list gets empty, it means that we have reached the desired the key, where we need to apply our replacement. So if the list is empty, the funtion replaces the dict[key] with the value

Categories

Resources