Flatten/merge dictionary with nested dictionaries - python

I've got the following dictionary example:
z1 = {
"ZH": {
"hosts": {
"zhsap001.domain.com": {
"active": "y",
"ip": "11.111.11.10",
"zone": "North"
},
"zhsap002.domain.com": {
"active": "y",
"ip": "11.111.11.11",
"zone": "North"
}
}
},
"BE": {
"hosts": {
"besap001.domain.com": {
"active": "y",
"ip": "22.222.2.20",
"zone": "Center"
},
"besap002.domain.com": {
"active": "y",
"ip": "10.214.4.58",
"zone": "Center"
}
}
}
}
And I'd like to "flatten" it to:
z2 = {
"zhsap001.domain.com": {
"active": "y",
"ip": "11.111.11.10",
"zone": "North"
},
"zhsap002.domain.com": {
"active": "y",
"ip": "11.111.11.11",
"zone": "North"
},
"besap001.domain.com": {
"active": "y",
"ip": "22.222.2.20",
"zone": "Center"
},
"besap002.domain.com": {
"active": "y",
"ip": "10.214.4.58",
"zone": "Center"
}
}
I can create z2 from z1 by running:
z2 = {}
for a in z1.values():
for b in a.values():
for (c,d) in b.items():
z2.update({c:d})
But I would like to achieve the same in a more Pythonized manner using a
comprehension expression or lambda function.

You could one-line it, but it won't necessarily be more readable that way.
z2 = {c_key: c for a in z1.values() for b in a.values() for c_key, c in b.items()}
I'd recommend naming the variables more clearly (I'm guessing what they mean here, you might want to change it)
z2 = {
url: url_info
for region in z1.values()
for host in region.values()
for url, url_info in host.items()
}
Also, you could improve your original code
z2 = {}
for a in z1.values():
for b in a.values():
z2 |= b
# The above requires python >= 3.9, alternatively use the below
# z2.update(b)

Related

Remove key but keep value in JSON [Python]

I need to "Semi-Flatten" a JSON object where i have a JSON object with nested items. I have tried to use the flat_json with pandas and other "flatten_json" and json_normalize code in stackoverflow but i end up with completely flatten JSON (something i do not need).
Here is the JSON structure:
[{
"Stat": {
"event": "03458188-abf9-431c-8144-ad49c1d069ed",
"id": "102e1bb1f28ca44b70d02d33380b13",
"number": "1121",
"source": "",
"datetime": "2023-01-13T00:00:00Z",
"status": "ok"
},
"Goal": {
"name": "goalname"
},
"Fordel": {
"company": "companyname"
},
"Land": {
"name": "landname"
}
}, {
"Stat": {
"event": "22222",
"id": "44444",
"number": "5555",
"source": "",
"datetime": "2023-01-13T00:00:00Z",
"status": "ok"
},
"Goal": {
"name": "goalname2"
},
"Fordel": {
"company": "companyname2"
},
"Land": {
"name_land": "landname2"
}
}]
The result i need is this:
[{
"event": "03458188-abf9-431c-8144-ad49c1d069ed",
"id": "102e1bb1f28ca44b70d02d33380b13",
"number": "1121",
"source": "",
"datetime": "2023-01-13T00:00:00Z",
"status": "ok",
"name": "goalname",
"company": "companyname",
"name_land": "landname"
}, {
"event": "22222",
"id": "44444",
"number": "5555",
"source": "",
"datetime": "2023-01-13T00:00:00Z",
"status": "ok",
"name": "goalname2",
"company": "companyname2",
"name_land": "landname2"
}]
If this can be used with pandas or other json packages it would be great.
Coded i have tried: (copy/paste from another question/answer)
def flatten_data(y):
out = {}
def flatten(x, name=''):
if type(x) is dict:
for a in x:
flatten(x[a], name + a + '_')
elif type(x) is list:
i = 0
for a in x:
flatten(a, name + str(i) + '_')
i += 1
else:
out[name[:-1]] = x
flatten(y)
return out
That gives me:
{
"0_event": "03458188-abf9-431c-8144-ad49c1d069ed",
"0_id": "102e1bb1f28ca44b70d02d33380b13",
......
"1_event": "102e1bb1f28ca44b70d02d33380b13",
"1_id": "102e1bb1f28ca44b70d02d33380b13",
etc...
}
Map the flatten_data function over the list instead of flattening the entire list.
result = list(map(flatten_data, source)))

Generate Hash Value for Nested JSON Object

I have two nested JSON objects with different order of elements and would like to generate hash value for both. Now, I'm comparing these two hash values and it needs to be same. How can I achieve this mechanism?
First JSON Object
{
"X":{
"Y":[
{
"A":"1",
"B":{
"b1":"2",
"b2":"2"
}
},
{
"C":"4",
"D":{
"d1":"5",
"d2":"6"
}
},
],
"Z":[
{
"E":{
"e1":"7",
"e2":"8"
},
"F":"9"
}
]
}
}
Second JSON Object
{
"X":{
"Y":[
{
"C":"4",
"D":{
"d1":"5",
"d2":"6"
}
},
{
"A":"1",
"B":{
"b1":"2",
"b2":"2"
}
},
],
"Z":[
{
"E":{
"e1":"7",
"e2":"8"
},
"F":"9"
}
]
}
}
So, here goal is I want to generate same hash value for both JSON object. How can I achieve this in Python or Golang?
The JSON object is unsorted as well the map[string]interface{}, so you should sort the maps. However, sorting could be complicated and time consuming.
Instead of using the objects I would like to use the JSON as string, this way the JSON can be Unmarshaled and the string can be sorted to create the SHA value.
var json1 = `
{
"X": {
"Y": [
{
"A": "1",
"B": {
"b1": "2",
"b2": "2"
}
},
{
"C": "4",
"D": {
"d1": "5",
"d2": "6"
}
}
],
"Z": [
{
"E": {
"e1": "7",
"e2": "8"
},
"F": "9"
}
]
}
}
`
var json2 = `
{
"X": {
"Y": [
{
"C": "4",
"D": {
"d1": "5",
"d2": "6"
}
},
{
"A": "1",
"B": {
"b1": "2",
"b2": "2"
}
}
],
"Z": [
{
"E": {
"e1": "7",
"e2": "8"
},
"F": "9"
}
]
}
}
`
type JSON struct {
X struct {
Y []struct {
A string `json:"A"`
B struct {
B1 string `json:"b1"`
B2 string `json:"b2"`
} `json:"B"`
C string `json:"C"`
D struct {
D1 string `json:"d1"`
D2 string `json:"d2"`
} `json:"D"`
} `json:"Y"`
Z []struct {
E struct {
E1 string `json:"e1"`
E2 string `json:"e2"`
} `json:"E"`
F string `json:"F"`
} `json:"Z"`
} `json:"X"`
}
func SortString(w string) string {
s := strings.Split(w, "")
sort.Strings(s)
return strings.Join(s, "")
}
func main() {
var v1, v2 interface{}
json.Unmarshal([]byte(json1), &v1)
json.Unmarshal([]byte(json2), &v2)
fmt.Println(reflect.DeepEqual(v1, v2))
var m1, m2 JSON
json.Unmarshal([]byte(json1), &m1)
json.Unmarshal([]byte(json2), &m2)
fmt.Println(reflect.DeepEqual(m1, m2))
json1 = SortString(json1)
json2 = SortString(json2)
fmt.Println(reflect.DeepEqual(json1, json2))
}
Keep in mind that the objects are unsorted, so you should evaluate if creating a JSONSort function is important (considering that JSON could be different each time).
go run json.go
false
false
true

Transforming streaming data into a json

I have a streaming data coming from a source and I was able to capture few important variables like ID, Timestamp and Vital signs. What I am trying to do is create a json file object and unload it into a file system. This is one of the examples:
for k in streaming:
id = k[1] ----------> 1
timestamp = k[2] ------> 1652304692
vsigns = k[3] -------> Nested dictionary
This is how vsigns looks like
"vsigns":
{
"ECG":
{
"VPB_FREQ": "0",
"STI": "+0.00"
},
"HR":
{
"HR_EKG": "87",
"HR_PPG_1": "87",
"HR_PULSED": "87"
},
"NIBP":
{
"NIBPS": "119",
"NIBPD": "88",
"NIBPM": "95"
}
}
And I want a json structure in the following format:
[{
"id": "1",
"ECG":
{
"timestamp": 1652304692,
"VPB_FREQ": "0",
"STI": "+0.00",
}
},
{
"id": "1",
"HR":
{
"timestamp": 1652304692,
"HR_EKG": "87",
"HR_PPG_1": "87",
"HR_PULSED": "87"
}
},
{
"id": "1",
"NIBP":
{
"timestamp": 1652304692,
"NIBPS": "119",
"NIBPD": "88",
"NIBPM": "95"
},
}]
I tried an approach but doesn't give me what I want. How do I get this right.
for k in streaming:
id = k[1]
timestamp = k[2]
vsigns = k[3]
vlist = []
for k, v in vsigns.items():
vdict = {"id": id,
k:{"timestamp":timestamp,
"vsigns": v}}
vlist.append(vdict)
print(vlist)
Output:
[{
"id": "1",
"ECG":
{
"timestamp": 1652951054.0,
"vsigns":
{
"VPB_FREQ": "0"
}
}
},
{
"id": "1",
"HR":
{
"timestamp": 1652951054.0,
"vsigns":
{
"HR_EKG": "126",
"HR_PPG_1": "127",
"HR_PULSED": "127"
}
}
},
{
"id": "1",
"NIBP":
{
"timestamp": 1652951054.0,
"vsigns":
{
"NIBPS": "95",
"NIBPD": "46",
"NIBPM": "62"
}
}
}
}]
The following piece of code worked for me:
for k in streaming:
id = k[1]
timestamp = k[2]
vsigns = k[3]
vlist = []
for k, v in vsigns.items():
v['timestamp'] = epoch_time
vdict = {"id": id,
k:v}
vlist.append(vdict)

Python Postfix order from JSON file

I've found a problem with some code that I am writing; when I extract the data from my JSON file and put it into POSTFIX order, when encountering functions such as Power, Sum, IF, NOT, it doesn't put them in the correct postfix order.
I've been trying to solve this for ages but I can't understand how to solve it.
Here are some examples of the JSON file:
sum(3+4*3*2+2,1,2,3)
{
"arguments": [{
"rightArgument": {
"value": "2",
"type": "constant"
},
"leftArgument": {
"rightArgument": {
"rightArgument": {
"value": "2",
"type": "constant"
},
"leftArgument": {
"rightArgument": {
"value": "3",
"type": "constant"
},
"leftArgument": {
"value": "4",
"type": "constant"
},
"type": "operation",
"operator": "*"
},
"type": "operation",
"operator": "*"
},
"leftArgument": {
"value": "3",
"type": "constant"
},
"type": "operation",
"operator": "+"
},
"type": "operation",
"operator": "+"
}, {
"value": "1",
"type": "constant"
}, {
"value": "2",
"type": "constant"
}, {
"value": "3",
"type": "constant"
}],
"name": "sum",
"type": "function"
}
Another example, power(2,3)+not(2=1):
{
"rightArgument": {
"arguments": [{
"rightArgument": {
"value": "1",
"type": "constant"
},
"leftArgument": {
"value": "2",
"type": "constant"
},
"type": "operation",
"operator": "="
}],
"name": "not",
"type": "function"
},
"leftArgument": {
"arguments": [{
"value": "2",
"type": "constant"
}, {
"value": "3",
"type": "constant"
}],
"name": "power",
"type": "function"
},
"type": "operation",
"operator": "+"
}
and finally: IF(1,IF(1,2,3),A1):
{
"arguments": [{
"value": "1",
"type": "constant"
}, {
"arguments": [{
"value": "1",
"type": "constant"
}, {
"value": "2",
"type": "constant"
}, {
"value": "3",
"type": "constant"
}],
"name": "IF",
"type": "function"
}, {
"cell": "A1",
"value": "",
"type": "cell"
}],
"name": "IF",
"type": "function"
}
As you can see I have to cater for a lot of different formats of formulae
currently my code to store the mathematical problem into a string is this:
def _getCurrentOperator(data):
if data["type"] == "operation":
_getCurrentOperator(data["rightArgument"])
_getCurrentOperator(data["leftArgument"])
valueList.append(data["operator"])
elif data["type"] == "group":
_getCurrentOperator(data["argument"])
elif data["type"] == "function":
if (data["name"] == "pi"):
valueList.append(3.14159265359)
else:
valueList.append(data["name"])
for i in range(len(data["arguments"])):
_getCurrentOperator(data["arguments"][i])
else:
if (data["value"]) == '':
valueList.append(data["cell"])
else:
valueList.append(float(data["value"]))
the input data is a JSON representation of the mathematical problem
I believe this is all the code you require to replicate the problem.
Currently it doesn't store the functions (power, IF, NOT) in non-postfix order however It does store the values in the right order.
If you want to make it postfix, you have to put the name of the function after the arguments. That's all.
def _getCurrentOperator(data):
if data["type"] == "operation":
_getCurrentOperator(data["rightArgument"])
_getCurrentOperator(data["leftArgument"])
valueList.append(data["operator"]) # here you do it right
...
elif data["type"] == "function":
if (data["name"] == "pi"):
valueList.append(3.14159265359)
else:
for i in range(len(data["arguments"])): # first the arguments...
_getCurrentOperator(data["arguments"][i])
valueList.append(data["name"]) # then the operation
else:
...
Also, you probably shouldn't handle pi separately. IMHO it's just another function with zero parameters.

Python jsonschema fails to validate enum of strings

So, I'm trying to define a schema for a set of axis constraints. Therefore, I would like to restrict the possible values of the "axis" element to ["x", "y", "z"].
Here is my current sample, and it's output.
JSON:
{
"name_patterns": [
{
"regex": "block[_-]?([\\d]*)",
"class": "block",
"id_group": 1
}
],
"relationships": [
{
"src_class": "block",
"dst_class": "block",
"constraints": {
"axis": "x"
}
}
]
}
Schema:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"name_patterns": {"type": "array",
"items": { "$ref": "#/definitions/name_entry" } },
"relationships": {"type": "array",
"items": { "anyof": [ {"$ref": "#/definitions/relation"} ] } }
},
"definitions": {
"name_entry": {
"type": "object",
"properties": {
"regex": {"type": "string"},
"class": {"type": "string"},
"id_group": {"type": "number"}
},
"required": ["regex", "class"]
},
"relation": {
"type": "object",
"properties": {
"src_class": {"type": "string"},
"dst_class": {"type": "string"},
"constraints": {
"type": "object",
"properties": {
"axis": {
"enum": ["x", "y", "z"]
}
},
"required": ["axis"]
}
},
"required": ["src_class", "dst_class", "constraints"]
}
}
}
How can I fix my schema to reject values which are not specified in the enumerator?
Your schema syntax is a bit off.
Firstly, you need to put property definitions inside properties:
{
"properties": {
"axis": {...}
}
}
Secondly, type defines the type (e.g. "string"), but you don't need it here. enum should just be directly inside the "axis" schema:
{
"properties": {
"axis": {
"enum": ["x", "y", "z"]
}
}
}

Categories

Resources