Home > Mobile >  Create complex object in python based on property names
Create complex object in python based on property names

Time:03-10

I am trying to create a complex object based on metadata I have. It is an array of attributes which I am iterating and trying to create a dict. For example below is the array

[
"attributes.entityAttributes[0].attributeName",
"attributes.entityAttributes[0].attributeValue",
"attributes.entityAttributes[0].attributeUOM",
"attributes.entityAttributes[1].attributeName",
"attributes.entityAttributes[1].attributeValue",
"attributes.entityAttributes[1].attributeUOM",
"attributes.entityAttributes[2].attributeName"
]

This array should give an output as below

{
    "attributes": {
        "entityAttributes": [
            {
                "attributeName": "",
                "attributeValue": "",
                "attributeUOM": ""
            },
            {
                "attributeName": "",
                "attributeValue": "",
                "attributeUOM": ""
            }
        ]
    }
}

I have written this logic but unable to get the desired output. It should work on both object and array given the metadata.

source_json = [
"attributes.entityAttributes[0].attributeName",
"attributes.entityAttributes[0].attributeValue",
"attributes.entityAttributes[0].attributeUOM",
"attributes.entityAttributes[1].attributeName",
"attributes.entityAttributes[1].attributeValue",
"attributes.entityAttributes[1].attributeUOM",
"attributes.entityAttributes[2].attributeName"
]

for row in source_json:
     propertyNames = row.split('.')
     temp = ''
     parent = {}
     parentArr = []
     parentObj = {}
     #if len(propertyNames) > 1:
     arrLength = len(propertyNames)
     for i, (current) in enumerate(zip(propertyNames)):
        if i ==0:
            if '[' in current:
                parent[current]=parentArr
            else:
                parent[current] = parentObj;
            temp = current
        if i>0 and i<arrLength-1:
            if '[' in current:
                parent[current]=parentArr
            else:
                parent[current] = parentObj;
            temp = current
        if i == arrLength-1:
            if '[' in current:
                parent[current]=parentArr
            else:
                parent[current] = parentObj;
            temp = current
            #temp[prev][current] =""
    #finalMapping[target] = target
print(parent)

Any help is much appreciated, Thanks in advance

CodePudding user response:

How about something like this:

import re
import json

source_json = [
"attributes.entityAttributes[0].attributeName",
"attributes.entityAttributes[0].attributeValue",
"attributes.entityAttributes[0].attributeUOM",
"attributes.entityAttributes[1].attributeName",
"attributes.entityAttributes[1].attributeValue",
"attributes.entityAttributes[1].attributeUOM",
"attributes.entityAttributes[2].attributeName"
]


def to_object(source_json):

    def add_attribute(target, attribute_list):
        head, tail = attribute_list[0], attribute_list[1:]
        if tail:
            add_attribute(target.setdefault(head,{}), tail)
        else:
            target[head] = ''
    
    target = {}
    for row in source_json:
        add_attribute(target, re.split(r'[\.\[\]] ',row))
    return target
    
  
print(json.dumps(to_object(source_json), indent=4))

Note that this will not exactly do what you requested. It interprets stores the array also as an object with keys '0' ... '2'. This makes it easier to implement and also more stable. What would you expect, when the input list missed the entries with entityAttributes[0]. Should the list include an empty element or something different. Anyway you save space by not including this element, which works only if you store the array in an object.

CodePudding user response:

First we should iterate over whole list and store each 3rd attributes, after that we could change this struct to our desired output:

from typing import Dict, List


source_json = [
    "attributes.entityAttributes[0].attributeName",
    "attributes.entityAttributes[0].attributeValue",
    "attributes.entityAttributes[0].attributeUOM",
    "attributes.entityAttributes[1].attributeName",
    "attributes.entityAttributes[1].attributeValue",
    "attributes.entityAttributes[1].attributeUOM",
    "attributes.entityAttributes[2].attributeName"
]


def accumulate(source: List) -> Dict:
    accumulator = {}
    for v in source:
        vs = v.split(".")
        root_attribute = vs[0]
        if not root_attribute in accumulator:
            accumulator[root_attribute] = {}

        i = vs[1].rfind('[')
        k = (vs[1][:i], vs[1][i 1:-1])

        if not k in accumulator[root_attribute]:
            accumulator[root_attribute][k] = {}
        accumulator[root_attribute][k][vs[2]] = ""
    return accumulator


def get_result(accumulated: Dict) -> Dict:
    result = {}
    for k, v in accumulated.items():
        result[k] = {}
        for (entity, idx), v1 in v.items():
            if not entity in result[k]:
                result[k][entity] = []
            if len(v1) == 3:
                result[k][entity].append(v1)
    return result


print(get_result(accumulate(source_json)))

The output will be:


{
    'attributes':
    {
        'entityAttributes':
        [
            {
                'attributeName': '',
                'attributeValue': '',
                'attributeUOM': ''
            },
            {'attributeName': '',
             'attributeValue': '',
             'attributeUOM': ''
            }
        ]
    }
}

In accumulate function we store 3rd level attributes in Dict with (entityAttributes, 0) ... (entityAttributes, 2) keys. In get_result function we convert Dict with (entityAttributes, 0) ... (entityAttributes, 2) keys to Dict from string to List.

  • Related