Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
530 views
in Technique[技术] by (71.8m points)

recursion - Javascript how to loop over a json array where we don't know how many nested array there is inside?

UPDATED SCRIPT

Here is an updated script I am working on:

function recursive(data, append_name) {
  for (parent_key in data) {
    var dim_type = data[parent_key]["type"];
    var dim_label = "";
    var dim_name = data[parent_key]["name"];
    if (typeof(data[parent_key]["label"])=="object") {
        dim_label = data[parent_key]["label"]["english"];
    }
    else {
        dim_label = data[parent_key]["label"];
    }
    
    for (child_key in data[parent_key]["children"]){
        //console.log(data[parent_key]["children"][child_key])
      var child_label = data[parent_key]["children"][child_key]["label"]["english"];

      if (append_name == "" || append_name == undefined) {
        var child_name = data[parent_key]["children"][child_key]["name"];
      } else {
        var child_name = append_name+"/"+data[parent_key]["children"][child_key]["name"];
      }
      if("children" in data[parent_key]["children"][child_key]) {
        recursive(data[parent_key]["children"][child_key]["children"], dim_name)
      }
      else {
        outputArray.push({"dim_label": dim_label,
                                            "dim_name": dim_name,
                          "child_name": dim_name+"/"+child_name,
                          "child_label": child_label})
      }
      console.log(outputArray, "")
    }
    //console.log(key, dim_label, dim_name, dim_type);
  }
}

The result is only showing 3 records out of 6, which are the first 3 rows only.

Here is a fiddle.

END OF EDIT


ORIGINAL QUESTION

I have JSON file I need to run a script over it to get 4 main fields:

  1. dim_label
  2. dim_name
  3. field_label
  4. field_name

The structure of the JSON array is as follows:

{
    "name": "Info",
    "title": "Info",
    "default_language": "default",
    "id_string": "...",
    "type": "survey",
    "children": [
        {
            "type": "text",
            "name": "basic_info",
            "label": "Basic Info",
            "children": [
                {
                    "type": "text",
                    "name": "name",
                    "label": {
                        "english": "What is your name"
                    }
                },
                {
                    "type": "text",
                    "name": "address",
                    "label": {
                        "english": "What is your address?"
                    }
                }
            ]
        },
        {
            "type": "text",
            "name": "more_data",
            "label": "More Data",
            "children": [
                {
                    "type": "text",
                    "name": "favourite_food",
                    "label": {
                        "english": "What is your favourite food?"
                    }
                },
                {
                    "type": "text",
                    "name": "favourite_destination",
                    "label": {
                        "english": "What is your favourite destination?"
                    },
                    "children": [
                        {
                            "type": "text",
                            "name": "france",
                            "label": {
                                "english": "France"
                            },
                            "type": "text",
                            "name": "usa",
                            "label": {
                                "english": "USA"
                            }
                        }
                    ]
                }
            ]
        },
        {
            "type": "number",
            "name": "estimated_income",
            "label": "What is your annual estimated income?"
        }
    ]
}

And the desired output should look like that:

enter image description here

Note that the last record is having the fields similar because this is no children array inside.

Notice that for the favourite_destination part, there a children array inside another one that's why at the end there is the following fields:

more_data/favourite_destination/france

more_data/favourite_destination/usa

So the field_name at the end will hold the full path of its parents names.

I tried this JavaScript script:

function recursive(arr, dim_label, dim_name){
    
    for (prop in arr) {
    var title = arr["title"];
    if (prop == "children") {
        for (child in arr[prop]){
        var dim_name = "";
        var dim_label = "";
        var field_name = "";
        var field_label = "";
        dim_name = arr[prop][child]["name"] +"/"+dim_name;
        type = arr[prop][child]["type"];
        field_name = dim_name+arr[prop][child]["name"];
        dim_label =arr[prop][child]["name"]["english"];
        field_label = "";
        if ("label" in arr[prop][child] ) {
         dim_label  = arr[prop][child]["label"]["english"];
         field_label = arr[prop][child]["label"]["english"]
        }
        else {
            dim_label = dim_name;
        }
        array.push({label: dim_label, name: dim_name});
        /* if (type != "calculate" && type != "select one") {
          if ("children" in arr[prop][child]) {
            recursive(arr[prop][child], dim_label, dim_name);
          }
        } */
        console.log(dim_name, dim_label, field_name, field_label)
      }
    }
  }
}

And the result was only 3 recrods:

"basic_info/", undefined, "basic_info/basic_info", undefined

"more_data/", undefined, "more_data/more_data", undefined

"estimated_income/", undefined, "estimated_income/estimated_income", undefined

Here is a jsfiddle.

How can I loop over an array that I don't know how many nested arrays there is inside to get the required information?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Here's an approach which separates the data traversal from the output formatting:

const getPaths = (obj) =>
  obj .children
    ? obj .children .flatMap (getPaths) .map (p => [obj, ...p])
    : [[obj]]

const extract = (data) =>
  getPaths (data) .map ((path) => ((
    field = path [path .length - 1], 
    parent = path .length > 2 ? path [path .length - 2] : path [path .length - 1]
  ) => ({
    dim_label: parent .label .english || parent .label,
    dim_name: path .slice (1, path .length > 2 ? -1 : Infinity) .map (n => n.name) .join('/'),
    field_label: field .label .english || field .label,
    field_name: path .slice(1) .map (n => n .name) .join('/')
  }))())

const data = {name: "Info", title: "Info", default_language: "default", id_string: "...", type: "survey", children: [{type: "text", name: "basic_info", label: "Basic Info", children: [{type: "text", name: "name", label: {english: "What is your name"}}, {type: "text", name: "address", label: {english: "What is your address?"}}]}, {type: "text", name: "more_data", label: "More Data", children: [{type: "text", name: "favourite_food", label: {english: "What is your favourite food?"}}, {type: "text", name: "favourite_destination", label: {english: "What is your favourite destination?"}, children: [{type: "text", name: "france", label: {english: "France"}}, {type: "text", name: "usa", label: {english: "USA"}}]}]}, {type: "number", name: "estimated_income", label: "What is your annual estimated income?"}]}

console .log (extract (data))

const display = (objs) => `<table><thead><tr>${Object.keys(objs[0]).map(k => `<th>${k}</th>`).join('')}</tr></thead><tbody>${objs.map(o => `<tr>${Object.values(o).map(v => `<td>${v}</td>`).join('')}</tr>`).join('')}</tbody></table>`

document.getElementById('output').innerHTML = display (extract (data))
.as-console-wrapper {max-height: 50% !important; bottom: 0}
table {border-collapse: collapse}
td, th { border: 1px solid #ccc}
th {background: #eee}
<div id="output"></div>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...