I have a flat JSON where keys represent different levels.
For example:
data = {
"name": "John",
"age": 30,
"address:city": "New-York",
"address:street": "5th avenue",
"address:number": 10,
}
As you can see keys contains :
which is the separator for the level.
I would like to convert it to have something like this:
wanted = {
"name": "John",
"age": 30,
"address": {
"city": "New-York",
"street": "5th avenue",
"number": 10
}
}
I'm working with Python but here I'm more looking just for logic advice, what would be the best approach to solve this problem in a generic way (not for this specific example only)
Thanks for your help
CodePudding user response:
I think an easy approach would be to create a method that maps this JSON to an object, and then convert the object to another object with attributes such as in the "wanted" one, and then you can simply convert the result object to JSON that will have "wanted" structure
CodePudding user response:
In Python:
def convert(inp, sep=':'):
output = {}
for key, value in inp.items():
*path, skey = key.split(sep)
dest = output
for p in path:
if p not in dest:
dest[p] = dict()
dest = dest[p]
dest[skey] = value
return output
CodePudding user response:
A recursive approach that supports multiple levels of nesting.
from typing import Any
def build(key: list[str], value: Any, res: dict):
k, *r = key
if r:
if not res.get(k):
res[k] = {}
build(r, value, res[k])
else:
res[k] = value
res = {}
for k, v in data.items():
build(k.split(":"), v, res)
CodePudding user response:
You can use jq:
jq 'reduce to_entries[] as {$key, $value} ({}; setpath($key / ":"; $value))'
Output
{
"name": "John",
"age": 30,
"address": {
"city": "New-York",
"street": "5th avenue",
"number": 10
}
}
If you want the keys sorted:
jq '. as $obj
| reduce keys[] as $key ({}; . * setpath($key | split(":"); $obj[$key]))'
Output
{
"address": {
"city": "New-York",
"number": 10,
"street": "5th avenue"
},
"age": 30,
"name": "John"
}
The code works for more than one nested level (e.g. additional entry "contact:phone:work": "110"
)
CodePudding user response:
# Data input
data = {
"name": "John",
"age": 30,
"address:city": "New-York",
"address:street": "5th avenue",
"address:number": 10,
}
# Initiate output
output = {
}
# Get keys in data
keys = data.keys()
# Iterate through keys
for i in keys:
# If there is a seperator, make sub-dcitionary. If not then proceed to add data normally.
if ":" in i:
# Extract subdictionary title and element name
split = i.split(":")
# If the subdictionary doesn't already exist, create it
if not (split[0] in output.keys()):
output[split[0]] = {}
# Add element to subdictionary
output[split[0]][split[1]]=data[i]
else:
output[i]=data[i]
# Print out results
print(output)
Results
{'name': 'John', 'age': 30, 'address': {'city': 'New-York', 'street': '5th avenue', 'number': 10}}