【问题标题】:List all nested properties with their full path in the containing object列出包含对象中的所有嵌套属性及其完整路径
【发布时间】:2018-01-16 15:26:14
【问题描述】:

我有一些存储在嵌套 JSON 中的名称数组,如下所示:

{
    "groupZ": {
        "names": [
            "Steve",
            "Henry"
        ]
    },
    "groupY": {
        "groupA": {
            "names": [
                "Laura"
            ]
        },
        "groupB": {
            "names": [
                "Alice",
                "Bob",
                "Neil"
            ]
        }
    },
    "groupX": {
        "groupC": {
            "groupD": {
                "names": [
                    "Steph"
                ]
            }
        },
        "groupE": {
            "names": [
                "Aaron",
                "Dave"
            ]
        }
    }
}

我试图弄清楚如何生成所有名称的列表,并在每个名称前面加上完整的组路径,所以它最终是这样的:

  • groupZ - 史蒂夫
  • groupZ - 亨利
  • groupY - groupA - 劳拉
  • groupY - groupB - Alice
  • groupY - groupB - Bob
  • groupY - groupB - 尼尔
  • groupX - groupC - groupD - Steph
  • groupX - groupE - Aaron
  • groupX - groupE - 戴夫

组名在每个级别都是唯一的,但除此之外可以称为任何名称。我知道我将需要递归调用一个函数,该函数在找到“名称”数组时停止,通过一个字符串添加到每个递归的前置,但遇到了真正的麻烦。到目前为止,这是我的代码:

var sPrepend = '';
function buildList(Groups, lastGroupName){

    for(var thisGroupName in Groups) {
        var thisGroup = Groups[thisGroupName];

        if(!thisGroup.names){
            sPrepend += (' - ' + thisGroupName);
            buildList(thisGroup, thisGroupName);
        }
        if(thisGroup.names){
            thisGroup.names.forEach(function(name){
                console.log(sPrepend, ' - ', name);
                //build the list item here.
            });
        }
    }
}
buildList(oGroups, '');

这让我很困惑,因为我无法更改 JSON 结构,但我确信这是可能的。感谢任何可以提供帮助的人!

【问题讨论】:

    标签: javascript arrays json javascript-objects nested-loops


    【解决方案1】:

    这对我有用:

    function buildList(group, accum, key) {
    
        // default helper parameters
        accum = accum || [];
        key = key || '';
    
        if (group.names) {  // add each name
            group.names.forEach(function(name) {
                accum.push(key + name);
            });
        } else {            // or recurse on each key
            Object.getOwnPropertyNames(group).forEach(function(gname) {
                buildList(group[gname], accum, key + gname + ' - ');
            });
        }
    
        return accum;
    }
    
    var list = buildList(oGroups);
    

    【讨论】:

      【解决方案2】:

      是的,你很接近。您只需确保将串联的组名(前一个 + 当前)传递给递归函数。

      Alnitak 的解决方案总体上更简洁。

      function buildList(Groups, lastGroupName){
      
          for(var thisGroupName in Groups) {
              var thisGroup = Groups[thisGroupName];
              
              var currGroupName = lastGroupName + ' - ' + thisGroupName;
      
              if(!thisGroup.names){
                  buildList(thisGroup, currGroupName);
              }
              if(thisGroup.names){
                  thisGroup.names.forEach(function(name){
                      console.log(currGroupName + ' - ' + name);
                      //build the list item here.
                  });
              }
          }
      }
      
      var oGroups = {
          "groupZ": {
              "names": [
                  "Steve",
                  "Henry"
              ]
          },
          "groupY": {
              "groupA": {
                  "names": [
                      "Laura"
                  ]
              },
              "groupB": {
                  "names": [
                      "Alice",
                      "Bob",
                      "Neil"
                  ]
              }
          },
          "groupX": {
              "groupC": {
                  "groupD": {
                      "names": [
                          "Steph"
                      ]
                  }
              },
              "groupE": {
                  "names": [
                      "Aaron",
                      "Dave"
                  ]
              }
          }
      };
      
      buildList(oGroups, '');

      我假设您也希望最终将其作为列表返回,这需要更多的努力。

      function buildList(Groups, lastGroupName){
      
          var ret = [];
      
          for(var thisGroupName in Groups) {
              var thisGroup = Groups[thisGroupName];
              
              var currGroupName = lastGroupName + ' - ' + thisGroupName;
      
              if(!thisGroup.names){
                  var childNames = buildList(thisGroup, currGroupName);
                  for(var i = 0; i < childNames.length; i++) {
                      ret.push(childNames[i]);
                  }
              }
              if(thisGroup.names){
                  thisGroup.names.forEach(function(name){
                      //console.log(currGroupName + ' - ' + name);
                      //build the list item here.
                      ret.push(currGroupName + ' - ' + name);
                  });
              }
          }
      
          return ret;
      }
      
      var oGroups = {
          "groupZ": {
              "names": [
                  "Steve",
                  "Henry"
              ]
          },
          "groupY": {
              "groupA": {
                  "names": [
                      "Laura"
                  ]
              },
              "groupB": {
                  "names": [
                      "Alice",
                      "Bob",
                      "Neil"
                  ]
              }
          },
          "groupX": {
              "groupC": {
                  "groupD": {
                      "names": [
                          "Steph"
                      ]
                  }
              },
              "groupE": {
                  "names": [
                      "Aaron",
                      "Dave"
                  ]
              }
          }
      };
      
      var x = buildList(oGroups, '');
      for(var i = 0; i < x.length; i++) {
          console.log(x[i]);
      }

      【讨论】:

        【解决方案3】:

        您可以将一个数组作为路径并在没有该参数的情况下调用该函数,因为它将被检查,如果不是truthy,则分配一个数组。

        在对象的keys的循环中,检查key是否为names,并将此数组与路径一起显示。

        如果键不等于names,则检查实际属性,如果它是可迭代对象,则使用具有实际键的扩展数组再次调用该函数。

        function buildList(object, path) {
            path = path || [];
            Object.keys(object).forEach(function (k) {
                if (k === 'names') {
                    object.names.forEach(function (name) {
                        console.log(path.concat(name).join(' - '));
                    });
                    return;
                }
                if (object[k] && typeof object[k] === 'object') {
                    buildList(object[k], path.concat(k));
                }
            });
        }
        
        var data = { groupZ: { names: ["Steve", "Henry"] }, groupY: { groupA: { names: ["Laura"] }, groupB: { names: ["Alice", "Bob", "Neil"] } }, groupX: { groupC: { groupD: { names: ["Steph"] } }, groupE: { names: ["Aaron", "Dave"] } } };
        
        buildList(data);
        .as-console-wrapper { max-height: 100% !important; top: 0; }

        【讨论】:

          猜你喜欢
          • 2021-12-26
          • 2018-01-08
          • 2021-05-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-02-21
          相关资源
          最近更新 更多