Python nested dictionary value convert to float or decimal from string - python

I have following dictionary
data={"Volkswagen":{
"Caddy Kombi":{
"2022":"285000000.00",
"2021":"212500000.00"
},
"Caddy Cargo":{
"2022":"193100000.00",
"2021":"190100000.00",
"2019":"1289456545.00"
}
},
"Tesla":{
"Model 3":{
"2022":"707160000.00",
"2021":"630000000.00",
"2020":"630000000.00"
},
"Model S":{
"2021":"630000000.00",
"2020":"630000000.00"
},
"Model X":{
"2021":"1102500000.00",
},
"Model Y":{
"2021":"735000000.00",
"2020":"735000000.00"
}
}}
I want to convert all the string prices to float values i.e "2021":285000000.00
I tried upto here but result is not expectd At the end I want same dictionary being converted to float
for i, y in data.items():
for k, x in y.items():
for z,q in (y[k].items()):
print(float(q))
dictionary = {
i: {
k: x
}
}
print(dictionary)

You can try recursion:
def to_float(o):
if isinstance(o, dict):
for k, v in o.items():
if isinstance(v, str):
o[k] = float(v)
else:
to_float(v)
elif isinstance(o, list):
for v in o:
to_float(v)
to_float(data)
print(data)
Prints:
{
"Volkswagen": {
"Caddy Kombi": {"2022": 285000000.0, "2021": 212500000.0},
"Caddy Cargo": {
"2022": 193100000.0,
"2021": 190100000.0,
"2019": 1289456545.0,
},
},
"Tesla": {
"Model 3": {
"2022": 707160000.0,
"2021": 630000000.0,
"2020": 630000000.0,
},
"Model S": {"2021": 630000000.0, "2020": 630000000.0},
"Model X": {"2021": 1102500000.0},
"Model Y": {"2021": 735000000.0, "2020": 735000000.0},
},
}

It helps to give your variables names that make sense. When you get to the last level, simply overwrite the value of the corresponding year. Since dicts are mutable, changing the value in the inner dictionary is reflected in the original dictionary.
for make, make_d in data.items():
for model, model_d in make_d.items():
for year, price in model_d.items():
model_d[year] = float(price)
print(data)
which gives:
{
"Volkswagen": {
"Caddy Kombi": {
"2022": 285000000.0,
"2021": 212500000.0
},
"Caddy Cargo": {
"2022": 193100000.0,
"2021": 190100000.0,
"2019": 1289456545.0
}
},
"Tesla": {
"Model 3": {
"2022": 707160000.0,
"2021": 630000000.0,
"2020": 630000000.0
},
"Model S": {
"2021": 630000000.0,
"2020": 630000000.0
},
"Model X": {
"2021": 1102500000.0
},
"Model Y": {
"2021": 735000000.0,
"2020": 735000000.0
}
}
}

Related

Python remove nested keys and a certain value's keys

1.Need to remove any value in any level of the keys that has a value null
2.Need to remove any chained key that is named key_2.key_c
Should result in the outcome block below.
Original json
{
"key_1": {
"key_a": 111111},
"key_2": {
"key_a": "value",
"key_b": null,
"key_c": {
"key_c_a": {
"key_c_b": "value"}
},
"key_d": [{"key_c": "value"}],
}
Outcome
{
"key_1": {
"key_a": 111111},
"key_2": {
"key_a": "value",
"key_d": [{"key_c": "value"}],
}
You can achieve this by recursively traversing the input JSON object and filtering out the unwanted values:
import json
def filter_json(obj):
if isinstance(obj, dict):
new_obj = {}
for k, v in obj.items():
if v is None:
continue
if k == "key_2":
new_obj[k] = filter_json({k2: v2 for k2, v2 in v.items() if k2 != "key_c"})
else:
new_obj[k] = filter_json(v)
return new_obj
elif isinstance(obj, list):
return [filter_json(elem) for elem in obj]
else:
return obj
Usage
json_str = '''
{
"key_1": {
"key_a": 111111
},
"key_2": {
"key_a": "value",
"key_b": null,
"key_c": {
"key_c_a": {
"key_c_b": "value"
}
},
"key_d": [
{
"key_c": "value"
}
]
}
}
'''
json_obj = json.loads(json_str)
filtered_obj = filter_json(json_obj)

How to print specific key with key and value

A = {
"Ajit": {
"Place": "Bharasar",
"Age": "20"
},
"Deepika": {
"Place": "Mankuva",
"Age": "19"
}
}
I want to print specific key Ajit with Ajit's key it self like:
{
'Ajit': {
'Place': 'Bharasar',
'Age':'20'
}
}
Do you mean:
A = {"Ajit":{"Place":"Bharasar","Age":"20"}, "Deepika":{"Place":"Mankuva","Age":"19"}}
key = "Ajit"
print(f"{{'{key}': {A[key]}}}")
And please remember to put four spaces before your code samples to get proper formatting
You just create a new Dict like the following code:
A = {
"Ajit": {
"Place": "Bharasar",
"Age": "20"
},
"Deepika": {
"Place": "Mankuva",
"Age": "19"
}
}
B = {
"Ajit": A["Ajit"]
}
print(B)
If you want Ajit value, you can get it with A["Ajit"]
However, if you want to have the key and its associated value, you can print
A = {
"Ajit": {
"Place": "Bharasar",
"Age": "20"
},
"Deepika": {
"Place": "Mankuva",
"Age": "19"
}
}
key = "Ajit"
print("{" + key + ":" + A[key] + "}")

Remove keys but keep values from dictionary

Let's say I have this dictionary:
{
"id": "132-sd-sa-23-a-1",
"data": {
"lastUpdated": { "S": "2020-07-22T21:39:20Z" },
"profile": {
"M": {
"address": { "L": [] },
"fakeField": { "S": "someValue" },
"someKey": { "M": { "firstName": { "S": "Test" } } }
}
},
"groups": {
"L": [{ "S": "hello world!" }]
}
}
}
How can I remove the "M", "S", "L", etc. keys from the dictionary but keep the values. So it would turn into this:
{
"id": "132-sd-sa-23-a-1",
"data": {
"lastUpdated": "2020-07-22T21:39:20Z",
"profile": {
"address": [],
"fakeField": "someValue",
"someKey": { "firstName": "Test" }
},
"groups": ["hello world!"]
}
}
I could turn the dictionary into a string, loop through it, and remove what's necessary but that doesn't seem efficient or fast. I can't save the original list as the output that I'm hoping for initially so I need to convert it myself.
Sounds like a job for recursion:
def unsml(obj):
if isinstance(obj, dict):
if len(obj) == 1:
(key, value), *_ = obj.items() # get the only key and value
if key in "SML":
return unsml(value)
return {
key: unsml(value) if isinstance(value, dict) else value
for key, value
in obj.items()
}
elif isinstance(obj, list):
return [unsml(value) for value in obj]
return obj
Then just do new_dict = unsml(old_dict).

Remove all occurences of a value from a nested dictionary

I have a nested dictionary as the following.
myDict= {
"id": 10,
"state": "MY LIST",
"Stars":
{
"BookA": {
"id": 10,
"state": "new book",
"Mystery": {
"AuthorA":
{
"id": "100",
"state": "thriller"
},
"AuthorB":
{
"id": "112",
"state": "horror"
}
},
"Thriller": {
"Store1":
{
"id": "300",
"state": "Old"
}
}
}
}
}
I want to return a dictionary which has all of the "state": "text" removed. So that means, I want to remove all the "state" fields and have an output as below.
I want it to be generic method as the dictionary could be nested on many levels.
myDict=
{
id: 10,
"Stars":
{
"BookA": {
"id": 10
"Mystery": {
"AuthorA":
{
"id": "100"
},
"AuthorB":
{
"id": "112"
}
},
"Thriller": {
"Store1":
{
"id": "300"
}
}
}
}
I tried the following but it doesnt seem to work. It only removes the "state": "MY LIST". May someone help me to resolve the issue?
def get(self):
removelist= ["state"]
new_dict = {}
for key, item in myDict.items():
if key not in removelist:
new_dict.update({key: item})
return new_dict
It doesnt remove all the "state" values.
You can use a DFS:
def remove_keys(d, keys):
if isinstance(d, dict):
return {k: remove_keys(v, keys) for k, v in d.items() if k not in keys}
else:
return d
The idea is to remove recursively the keys from subtrees: for every subtree that is a nested dict, return a dict without the keys to remove, using a dict comprehension; for every leaf (that is a single value), just return the value.
Test:
from pprint import pprint
pprint(remove_keys(myDict, ['state']))
Output:
{'Stars': {'BookA': {'Mystery': {'AuthorA': {'id': '100'},
'AuthorB': {'id': '112'}},
'Thriller': {'Store1': {'id': '300'}},
'id': 10}},
'id': 10}
The problem is you aren't handling the nested dictionaries.
def get(self):
removelist= ["state"]
new_dict = {}
for key, item in myDict.items():
if key not in removelist:
new_dict.update({key: item})
if isinstance(item, dict):
# You'll need to handle this use case.
return new_dict
To elaborate, lets look back at your dictionary:
myDict= {
"id": 10, # int
"state": "MY LIST", # string
"Stars": { # dictionary
"BookA": {
"id": 10, # int
"state": "new book", # string
"Mystery": { # dictionary
"AuthorA": {
"id": "100",
"state": "thriller"
},
"AuthorB": {
"id": "112",
"state": "horror"
}
},
"Thriller": {
"Store1": {
"id": "300",
"state": "Old"
}
}
}
}
}
I commented in the types for clarity. Your code is currently parsing myDict and ignoring the key "state". Once you hit the value "Stars", you need to parse that dictionary to also ignore the key "state".

Convert float string to float in json

I have a json(test.json) file with the below data. I have around 10000 records. I need to convert value from string to float write in the new file(test1.json). How can I do do this from Python?
{
"name":"test001",
"cat":"test",
"loc":"x loc",
"ings":[
{
"name":"rrrrrr",
"value":"13.0"
},
{
"name":"hhhh",
"value":"18.0"
}
],
"nums":[
{
"name":"kkkk",
"value":"82.05"
},
{
"name":"uuuuu",
"value":"53.55"
}
]
},
{
"name":"test002",
"cat":"test1",
"loc":"y loc",
"ings":[
{
"name":"trtrtr",
"value":"11.0"
},
{
"name":"wewew",
"value":"19.0"
}
],
"nums":[
{
"name":"iuyt",
"value":"122.05"
},
{
"name":"oiui",
"value":"15.5"
}
]
}
resulting json file(test1.json) should be like below...
{
"name":"test001",
"cat":"test",
"loc":"x loc",
"ings":[
{
"name":"rrrrrr",
"value":13.0
},
{
"name":"hhhh",
"value":18.0
}
],
"nums":[
{
"name":"kkkk",
"value":82.05
},
{
"name":"uuuuu",
"value":53.55
}
]
},
{
"name":"test002",
"cat":"test1",
"loc":"y loc",
"ings":[
{
"name":"trtrtr",
"value":11.0
},
{
"name":"wewew",
"value":19.0
}
],
"nums":[
{
"name":"iuyt",
"value":122.05
},
{
"name":"oiui",
"value":15.5
}
]
}
You can provide an object_hook to the json.loads method which will allow you to modify any object (dicts) found within the json:
import json
json_data = """
[{
"name":"test001",
"cat":"test",
"loc":"x loc",
"ings":[
{
"name":"rrrrrr",
"value":"13.0"
},
{
"name":"hhhh",
"value":"18.0"
}
],
"nums":[
{
"name":"kkkk",
"value":"82.05"
},
{
"name":"uuuuu",
"value":"53.55"
}
]
},
{
"name":"test002",
"cat":"test1",
"loc":"y loc",
"ings":[
{
"name":"trtrtr",
"value":"11.0"
},
{
"name":"wewew",
"value":"19.0"
}
],
"nums":[
{
"name":"iuyt",
"value":"122.05"
},
{
"name":"oiui",
"value":"15.5"
}
]
}]
"""
def as_float(obj):
"""Checks each dict passed to this function if it contains the key "value"
Args:
obj (dict): The object to decode
Returns:
dict: The new dictionary with changes if necessary
"""
if "value" in obj:
obj["value"] = float(obj["value"])
return obj
if __name__ == '__main__':
l = json.loads(json_data, object_hook=as_float)
print (json.dumps(l, indent=4))
This results in what you want:
[
{
"loc": "x loc",
"ings": [
{
"name": "rrrrrr",
"value": 13.0
},
{
"name": "hhhh",
"value": 18.0
}
],
"name": "test001",
"nums": [
{
"name": "kkkk",
"value": 82.05
},
{
"name": "uuuuu",
"value": 53.55
}
],
"cat": "test"
},
{
"loc": "y loc",
"ings": [
{
"name": "trtrtr",
"value": 11.0
},
{
"name": "wewew",
"value": 19.0
}
],
"name": "test002",
"nums": [
{
"name": "iuyt",
"value": 122.05
},
{
"name": "oiui",
"value": 15.5
}
],
"cat": "test1"
}
]
To write to a file instead:
with open("out.json", "w+") as out:
json.dump(l, out, indent=4)
You would need to recursively traverse the data and convert anything that looks like a float to a float:
def fix_floats(data):
if isinstance(data,list):
iterator = enumerate(data)
elif isinstance(data,dict):
iterator = data.items()
else:
raise TypeError("can only traverse list or dict")
for i,value in iterator:
if isinstance(value,(list,dict)):
fix_floats(value)
elif isinstance(value,str):
try:
data[i] = float(value)
except ValueError:
pass
It should do the trick:
my_data = [
{ "name" : "rrrrrr",
"value" : "13.0" },
{ "name" : "hhhh",
"value" : "18.0" },
]
fix_floats(my_data)
>>> my_data
[{'name': 'rrrrrr', 'value': 13.0}, {'name': 'hhhh', 'value': 18.0}]
If you have a single or specific key value object, you can reiterate the value containing alphabetical strings or numerical strings, then map and check against their type with string.isnumeric():
dict = { 'a':'100', 'b':'200', 'c':'300', 'd':'four_hundred', 'e':'500' }
dict_parse = {k: int(v) if v.isnumeric() else v for k, v in dict.items()}
>>> dict_parse
{ 'a': 100, 'b': 200, 'c': 300, 'd':'four_hundred', 'e':500}
when dealing with float numbers amend the if statement to replace decimal point, you can apply same principal to negative numbers:
dict = { 'a':'10.0', 'b':'20.12', 'c':'300.3', 'd':'four_hundred', 'e':'500' }
dict_parse = {k: float(v) if v.replace(".", "").isnumeric() else v for k, v in dict.items()}
>>> dict_parse
{ 'a': 10.0, 'b': 20.12, 'c': 300.3, 'd':'four_hundred', 'e':500}

Categories