列出所有嵌套属性及其在包含对象中的完整路径

时间:2018-01-16 15:26:14

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

我有一些存储在嵌套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 - Henry
  • groupY - groupA - Laura
  • groupY - groupB - Alice
  • groupY - groupB - Bob
  • groupY - groupB - Neil
  • groupX - groupC - groupD - Steph
  • groupX - groupE - Aaron
  • groupX - groupE - Dave

组名在每个级别都是唯一的,但除此之外可以被称为任何东西。我知道我需要递归调用一个函数,当它找到一个" name"数组,通过一个字符串来添加到每个递归的前置,但有真正的麻烦。到目前为止,这是我的代码:

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结构,但我确信这是可能的,这让我很难过。谢谢任何可以提供帮助的人!

3 个答案:

答案 0 :(得分:3)

这对我有用:

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);

答案 1 :(得分:0)

是的,你很亲密。您只需要确保将连接的组名称(previous + current)传递给递归函数。

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]);
}

答案 2 :(得分:0)

您可以为路径选择一个数组并调用不带该参数的函数,因为它将被检查,如果不是truthy,则会分配一个数组。

在对象的键的循环中,检查键是否为names,并且该数组与路径一起显示。

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

&#13;
&#13;
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);
&#13;
.as-console-wrapper { max-height: 100% !important; top: 0; }
&#13;
&#13;
&#13;