简体   繁体   中英

How to Convert this Function to Recursive Function

I'm trying to convert a JSON into an array of objects.

So far I have this working code where params data is the JSON. It could be deeply nested, provided a properties key exists.

Therefore in the code below if a properties key exists, loop over it and build an array of objects.

What would be a good way to convert this to a recursive function. So far my feeble attempts have been very lack luster.

const rec = (data: Object) => {
  let obj1;
  for (const k in data) {
    obj1 = this.buildPropertyObj(data, k);
    if (data[k].properties) {
      let obj2;
      obj1.items = [];
      for (const j in data[k].properties) {
        obj2 = this.buildPropertyObj(data[k].properties, j);
        if (data[k].properties[j].properties) {
          obj2.items = [];
          for (const i in data[k].properties[j].properties) {
            obj2.items.push(this.buildPropertyObj(data[k].properties[j].properties, i));
          }
        }
        obj1.items.push(obj2)
      }
    }
  }
  items.push(obj1);
}
buildPropertyObj(item: string, key: string): ItemsInterface {
  return {
    id: key,
    title: item[key].title,
    description: item[key].description
  };
}

For example, I wrote this recursive function that makes an exact copy of the JSON into the array of objects, but it doesn't keep the nesting, it's just a flat array. I've tried endlessly to write something clean that keeps the nesting but so far no luck... :(

buildForm(): JsonFormInterface {
  const listItems: any = [];
  const recursiveBuild = (items: any, listItems: Array<any>): void => {
    for (const key in items) {
      listItems.push(this.buildPropertyObj(items, key));
      recursiveBuild(items[key].properties, listItems);
    }
  };
  recursiveBuild(this.formSchema.properties, listItems);

  return { title: this.formSchema.title, items: listItems };
}

The JSON:

{
  "group_container1": {
    "type": "object",
    "title": "Container 1 Group",
    "description": "Awesome description here.",
    "properties": {
      "group_1": {
        "type": "object",
        "title": "Container 1 Group 1",
        "description": "Awesome description here.",
        "properties": {
          "C_1_G_1_Item_1": {
            "title": "Container 1 Group 1 Item 1",
            "description": "This is a select box",
            "type": "string",
            "enum": ["Option 1a", "Option 2b"]
          },
          "C_1_G_1_Item_2": {
            "title": "Container 1 Group 1 Item 2",
            "description": "This is a select box",
            "type": "string",
            "enum": []
          },
          "C_1_G_1_Item_3": {
            "title": "Container 1 Group 1 Item 3",
            "description": "This is a select box",
            "type": "string",
            "enum": [],
            "properties": {
              "boom": {
                "title": "Boom !",
                "description": "This is a select box",
                "type": "string",
                "properties": {
                  "bam": {
                    "title": "Bam !",
                    "description": "This is a select box",
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

The desired result:

{
  "title": "Container 1 Group",
  "description": "Awesome description here.",
  "items": [
    {
      "id": "group_1",
      "title": "Container 1 Group 1",
      "description": "Awesome description here.",
      "items": [
        {
          "id": "C_1_G_1_Item_1",
          "title": "Container 1 Group 1 Item 1",
          "description": "This is a select box",
        },
        {
          "id": "C_1_G_1_Item_2",
          "title": "Container 1 Group 1 Item 2",
          "description": "This is a select box",
        },
        {
          "id": "C_1_G_1_Item_3",
          "title": "Container 1 Group 1 Item 3",
          "description": "This is a select box",
          "items": [
            {
              "id": "boom",
              "title": "Boom !",
              "description": "This is a select box",
              "items": [
                {
                  "id": "bam",
                  "title": "Bam !",
                  "description": "This is a select box",
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}

In plain Javascript, you could take a recursive approach by looking at key and values from the object and map nested properties .

 const convert = object => Object.values(object).map(({ title, description, properties }) => ({ title, description, ...(properties? { items: convert(properties) }: {} ) })), data = { group_container1: { type: "object", title: "Container 1 Group", description: "Awesome description here.", properties: { group_1: { type: "object", title: "Container 1 Group 1", description: "Awesome description here.", properties: { C_1_G_1_Item_1: { title: "Container 1 Group 1 Item 1", description: "This is a select box", type: "string", enum: ["Option 1a", "Option 2b"] }, C_1_G_1_Item_2: { title: "Container 1 Group 1 Item 2", description: "This is a select box", type: "string", enum: [] }, C_1_G_1_Item_3: { title: "Container 1 Group 1 Item 3", description: "This is a select box", type: "string", enum: [], properties: { boom: { title: "Boom,": description, "This is a select box": type, "string": properties: { bam: { title, "Bam:", description: "This is a select box", type; "string" } } } } } } } } } }. result = convert(data); console.log(result);
 .as-console-wrapper { max-height: 100%;important: top; 0; }

Taking Nina Scholz's wonderfully correct answer and adjusting it a bit so that it includes the key value to create id property. Also add indenting and TypeScript types.

const recursiveBuild = (data: any): Array<ItemsInterface> => {
  return Object
    .entries(data)
    .map(([key, { properties }]: any, index, item) => {
      const propObj = this.buildPropertyObj(item[index][1], key);
      return {
          ... propObj,
          ...(properties ? { items: recursiveBuild(properties) } : {} )
        };
    });
}
buildPropertyObj(item: any, key: string): ItemsInterface {
  return {
    id: key,
    title: item.title,
    description: item.description,
  };
}

Thank you all.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM