Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/451.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何递归地取消嵌套对象的嵌套?_Javascript_Recursion - Fatal编程技术网

Javascript 如何递归地取消嵌套对象的嵌套?

Javascript 如何递归地取消嵌套对象的嵌套?,javascript,recursion,Javascript,Recursion,我正在使用一个数组,该数组可能具有许多不可预测嵌套的对象/数组。每个对象都将始终具有name属性,其中一些对象可能具有sub_字段数组。我希望剥离对象,使每个对象的键等于name属性,同时保持原始对象的嵌套级别 下面是一个我可以开始的例子: var data = [ { foo: 'foo', bar: 'bar', name: 'Object 1' }, { foo: 'foo', bar:

我正在使用一个数组,该数组可能具有许多不可预测嵌套的对象/数组。每个对象都将始终具有name属性,其中一些对象可能具有sub_字段数组。我希望剥离对象,使每个对象的键等于name属性,同时保持原始对象的嵌套级别

下面是一个我可以开始的例子:

var data = [
    {
        foo: 'foo',
        bar: 'bar',
        name: 'Object 1'
    },
    {
        foo: 'foo',
        bar: 'bar',
        name: 'Object 2'
    },
    {
        foo: 'foo',
        bar: 'bar',
        name: 'Object 3',
        sub_fields : [
            {
                foo: 'foo',
                bar: 'bar',
                name: 'SubLevel Object 1',
                sub_fields: [
                    {
                        foo: 'foo',
                        bar: 'bar',
                        name: 'SubLevel Object 1',
                    }
                ]
            },
            {
                foo: 'foo',
                bar: 'bar',
                name: 'SubLevel Object 2',
                sub_fields: [
                    {
                        foo: 'foo',
                        bar: 'bar',
                        name: 'SubLevel Object 1',
                    },
                    {
                        foo: 'foo',
                        bar: 'bar',
                        name: 'SubLevel Object 2',
                    },
                    {
                        foo: 'foo',
                        bar: 'bar',
                        name: 'SubLevel Object 3',
                        sub_fields: [
                            {
                                foo: 'foo',
                                bar: 'bar',
                                name: 'SubLevel Object 1'
                            }
                        ]
                    }
                ]
            }
        ]
    }
]
理想情况下,我的目标是获取原始数据并创建如下内容:

var newData = {
    'Object 1': null,
    'Object 2': null,
    'Object 3': {
        'Sublevel Object 1': {
            'Sublevel Object 1': null
        },
        'Sublevel Object 2': {
            'Sublevel Object 1': null,
            'Sublevel Object 2': null,
            'Sublevel Object 3': {
                  'Sublevel Object 1': null
             }
        }
    }
}
我觉得我花了太多的时间在这上面,而我知道一定有某种递归函数来实现它——我只是对我正在努力寻找解决方案的这类事情太缺乏经验了

有人能告诉我我能做什么吗

编辑 这是我试过的。这是一个混乱的局面,事实上太零碎了,太尴尬了哈哈,但是,真诚地说,我不想让你认为我没有试着自己解决这个问题:

另外,正在解析的字段组来自我正在处理的更相关的JSON数据。。。不是上面的foo/bar示例

var parsed_field_group = JSON.parse(JSON.stringify(field_group));
var fields = field_group[0].fields;

function removeKeys(obj, keys) {
    for (var prop in obj) {
        if(obj.hasOwnProperty(prop)) {
            switch(typeof(obj[prop])) {
                case 'object':
                    if(keys.indexOf(prop) > -1) {
                        delete obj[prop];
                    } else {
                        removeKeys(obj[prop], keys);
                    }
                    break;
                default:
                    if(!keys.includes(prop)) {
                        delete obj[prop];
                    }
                    break;
            }
        }
    }
}

removeKeys(fields, ['name', 'wrapper'])

console.log(fields)

var newJson = Object.create(null);
fields.forEach(field => {
    if (field.hasOwnProperty('sub_fields')) {
        newJson[field.name] = field
    } else {
        newJson[field.name] = null
    }
})

function handleSubFields(obj, key) {
    for (var prop in obj) {
        if (obj[prop]) {
            obj[prop][key].forEach(field => {
                if (field.hasOwnProperty(key)) {
                    obj[prop][field.name] = field
                } else {
                    obj[prop][field.name] = null
                }
            })
            delete obj[prop][key]
            delete obj[prop].name
        }
    }
}
handleSubFields(newJson, 'sub_fields')

console.log(newJson)
上面的内容让我非常接近,但我最终被困在嵌套在对象第一个子字段中的子字段上


我知道上面的话一定很可笑。请善待我!:-

是的,使用递归非常容易。以下是您的基本情况:

您收到的不是对象的东西-返回null。 那么您的基本递归情况是:

收到一个对象后,用一个属性构造一个新对象,该属性的名称是对象的名称,值是函数的递归应用程序。 最后,如果您有数组,您只需处理发生的情况:

遍历整个数组并针对每个元素调用函数。将所有结果收集到同一对象中。 var data=[{foo:'foo',bar:'bar',name:'Object 1'},{foo:'foo',bar:'bar',name:'Object 2'},{foo:'foo',bar:'bar',name:'Object 3',sub_字段:[{foo:'foo',bar:'bar',name:'sub sub sub_字段:[{foo:'foo:'foo',bar:'bar',name:'subvel Object 1',},{foo:'foo',bar:'bar',name:'subvell Object 2',sub_字段:[{foo:'foo',bar:'subvell Object 1',},{foo:'foo',bar:'bar',name:'subvell Object 2',},{foo:'foo',bar:'bar',name:'subvell Object 3',sub sub_字段:[{foo:'foo:'foo',bar:'bar:'bar',name:'subvell Object 1'}]}] 函数toObjdata{ 如果数据==null,则返回null; //在同一对象中收集对函数的所有递归调用 if Array.isArraydata return data.reduceac,data=>{…acc,…toObjdata},{} //从'name'属性和函数的递归应用程序生成新对象 返回{[data.name]:toObjdata.sub_字段,{}; }
console.logtoObjdata是的,使用递归非常容易。下面是您的基本情况:

您收到的不是对象的东西-返回null。 那么您的基本递归情况是:

收到一个对象后,用一个属性构造一个新对象,该属性的名称是对象的名称,值是函数的递归应用程序。 最后,如果您有数组,您只需处理发生的情况:

遍历整个数组并针对每个元素调用函数。将所有结果收集到同一个对象中。 var data=[{foo:'foo',bar:'bar',name:'Object 1'},{foo:'foo',bar:'bar',name:'Object 2'},{foo:'foo',bar:'bar',name:'Object 3',sub_字段:[{foo:'foo',bar:'bar',name:'sub sub sub_字段:[{foo:'foo:'foo',bar:'bar',name:'subvel Object 1',},{foo:'foo',bar:'bar',name:'subvell Object 2',sub_字段:[{foo:'foo',bar:'subvell Object 1',},{foo:'foo',bar:'bar',name:'subvell Object 2',},{foo:'foo',bar:'bar',name:'subvell Object 3',sub sub_字段:[{foo:'foo:'foo',bar:'bar:'bar',name:'subvell Object 1'}]}] 函数toObjdata{ 如果数据==null,则返回null; //在同一对象中收集对函数的所有递归调用 if Array.isArraydata return data.reduceac,data=>{…acc,…toObjdata},{} //从'name'属性和函数的递归应用程序生成新对象 返回{[data.name]:toObjdata.sub_字段,{}; } console.logtoObjdata转换

{ foo: 'foo'
, bar: 'bar'
, name: 'Object 1'
}
进入:

您可以使用此功能:

const transform =
  ({name}) =>
    ({[name]: null});
如果它包含子字段呢

将变换的结果指定给sub_字段中的所有对象,而不是指定null

我们可以修改transform以支持:

const transform =
  ({name, sub_fields}) =>
    ( { [name]: sub_fields
          ? Object.assign({}, ...sub_fields.map(transform))
          : null
      }
    );
现在,您可以将相同的原理应用于我们的阵列以生成最终对象:

常数变换= {name,sub_fields}=> {[name]:子字段 ?Object.assign{},…sub_fields.maptransform :null } ; console.log Object.assign{},…data.maptransform ; const data=[{foo:foo,bar:bar,name:Object 1},{foo:foo,bar:bar,name:Object 2},{foo:f oo,bar:bar,name:Object 3,sub_字段:[{foo:foo,bar:bar,name:SubLevel Object 1,sub_字段:[{foo:foo,bar:bar,name:SubLevel Object 1}},{foo:foo,bar:bar,name:SubLevel Object 2,sub_字段:[{foo:foo,bar:bar,name:SubLevel Object 1},{foo:foo,bar:bar,name:SubLevel Object 2},{foo:foo,bar:bar,name:SubLevel Object 3,SubLevel字段:[{foo:foo,bar:bar,名称:子级对象1}]}]}]}]; 转化

{ foo: 'foo'
, bar: 'bar'
, name: 'Object 1'
}
进入:

您可以使用此功能:

const transform =
  ({name}) =>
    ({[name]: null});
如果它包含子字段呢

将变换的结果指定给sub_字段中的所有对象,而不是指定null

我们可以修改transform以支持:

const transform =
  ({name, sub_fields}) =>
    ( { [name]: sub_fields
          ? Object.assign({}, ...sub_fields.map(transform))
          : null
      }
    );
现在,您可以将相同的原理应用于我们的阵列以生成最终对象:

常数变换= {name,sub_fields}=> {[name]:子字段 ?Object.assign{},…sub_fields.maptransform :null } ; console.log Object.assign{},…data.maptransform ; const data=[{foo:foo,bar:bar,name:Object 1},{foo:foo,bar:bar,name:Object 2},{foo:foo,bar:bar,name:Object 3,sub_字段:[{foo:foo,bar:bar,name:SubLevel Object 1,sub_字段:[{foo:foo,bar:bar,name:SubLevel Object 1},{foo:foo,bar:bar,name:SubLevel Object 2,SubLevel fields:[{foo:foo,bar,bar:SubLevel,{foo:foo,bar:bar,名称:子级对象3,子_字段:[{foo:foo,bar:bar,名称:子级对象1}]}];
我使用递归开发这个函数来实现您的目标,因为我知道在您的对象中总是有一个名为“name”的属性,有时还有其他名为“sub_fields”的属性

function rebuildNameObject(objArr = [], resObj = {}){
  objArr.forEach(obj => {
        Object.keys(obj).forEach(item => {
          if (item === 'name'){
            resObj[obj[item]] = null;
          }

          if(item === 'sub_fields'){
            resObj[obj['name']] = rebuildNameObject(obj[item]);
          }

        });
    });
  return resObj;
}

我使用递归开发这个函数来实现您的目标,因为我知道在您的对象中总是有一个名为“name”的属性,有时还有其他名为“sub_fields”的属性

function rebuildNameObject(objArr = [], resObj = {}){
  objArr.forEach(obj => {
        Object.keys(obj).forEach(item => {
          if (item === 'name'){
            resObj[obj[item]] = null;
          }

          if(item === 'sub_fields'){
            resObj[obj['name']] = rebuildNameObject(obj[item]);
          }

        });
    });
  return resObj;
}

这里已经有好几个很好的答案,还有customcommander的一个很好的解释。我认为这种选择值得考虑,原因有几个:

只有在没有更明确的内容时,我才选择reduce。虽然它是最强大的数组迭代方法,但它的级别较低,对我来说,它不像map和Object.assign的组合那样具有自文档功能。与forEach相比,这更为重要,forEach根本没有固有的语义

我个人更喜欢使用表达式而不是语句,并且更喜欢使用单个表达式箭头函数,而不是使用一个或多个返回语句

虽然customcommander的阐述很棒,而且我非常喜欢这种技术,但是转换函数仍然需要一个包装器来获得预期的输出。包装器绝对没有问题,尽管我会为此添加另一个函数。但是我在这里提出的版本使用类似的技术管理同样的事情,并且不需要包装就不会增加复杂性

常量转换=obj=> 数组。isArray对象 ? Object.assign…obj.map变换 :{[obj.name]:'sub_fields'在obj中?transform obj.sub_fields:null} const data=[{foo:'foo',bar:'bar',name:'Object 1'},{foo:'foo',bar:'bar',name:'Object 2'},{foo:'foo',bar:'bar',name:'Object 3',sub_字段:[{foo:'foo',bar:'bar',name:'subvel Object 1',sub sub_字段:[{foo:'foo:'foo',bar:'bar',name:'subvel Object 1',},{foo:'foo',bar:'bar',name:'subvell Object 2',sub_字段:[{foo:'foo',bar:'subvell Object 1',},{foo:'foo',bar:'bar',name:'subvell Object 2',},{foo:'foo',bar:'bar',name:'subvell Object 3',sub sub_字段:[{foo:'foo:'foo',bar:'bar:'bar',name:'subvell Object 1'}]}]
console.log transform data已经有了几个很好的答案,customcommander也给出了一个很好的解释。我认为这个替代方案值得考虑,原因有几个:

只有在没有更明确的方法可用时,我才选择reduce。虽然它是最强大的数组迭代方法,但它的级别较低,而且对我来说,它不像map和Object.assign的组合那样具有自文档功能。与forEach相比,这一点更为重要,因为forEach根本没有固有的语义

我个人更喜欢使用表达式而不是语句,并且更喜欢使用单个表达式箭头函数,而不是使用一个或多个返回语句

虽然customcommander的阐述很棒,而且我非常喜欢这项技术,但转换函数仍然需要一个包装器来获得预期的输出。包装器绝对没有问题,尽管我会为此添加另一个函数。但是我在这里提出的版本使用类似的技术管理同样的事情,并且没有添加复杂的内容不需要包装就可以实现

常量转换=obj=> 数组。isArray对象 ?对象分配…对象映射变换 :{[obj.name]:'sub_fields'在obj中?transform obj.sub_fields:null} const data=[{foo:'foo',bar:'bar',name:'Object 1'},{foo:'foo',bar:'bar',name:'Object 2'},{foo:'foo',bar:'bar',name:'Object 3',子字段 :[{foo:'foo',bar:'bar',name:'SubLevel Object 1',sub_字段:[{foo:'foo',bar:'bar',name:'SubLevel Object 1',name:'SubLevel Object 1',sub_字段:[{foo:'foo',bar:'bar',name:'SubLevel Object 1',},{foo:'foo',bar:'bar',name:'SubLevel Object 2',},{foo:'foo',bar:'bar',name:'SubLevel Object 3',sub_字段:[{foo:'foo',bar:'bar',name:'SubLevel Object 1'}]}]
log转换数据如果它不是一个字符串,它不是。你能告诉我们你尝试了什么吗?它不需要工作或完成,我们只是希望看到一个诚信的努力第一。Andreas是正确的,问题中的不是JSON,而是一个对象文字表达式。我编写了一个解决方案,并注意到,对于Sublevel object 3:null,您的预期结果是奇怪的,因为输入中有一个sub_字段。@Andreas如果它不是字符串,它不是JSON,您可能需要澄清该语句。布尔和数字是有效的JSON实体example@customcommander是的,说JSON是字符串并不完全准确;更准确的是,JSON是包含定义良好的结构的文本。我们之所以说它是字符串,是因为在任何编程语言中使用它时,它都是字符串。对象文字表达式通常被错误地称为JSON,但因为它们不是字符串,所以实际上不是JSON。在这个问题中,对象键不是双引号,这对于JSON是必需的,但对于对象文本表达式则不是。JSON实际上是JS对象的字符串表示。如果它不是字符串,那么它就不是。您能告诉我们您尝试了什么吗?它不需要工作或完成,我们只是希望看到一个诚信的努力第一。Andreas是正确的,问题中的不是JSON,而是一个对象文字表达式。我编写了一个解决方案,并注意到,对于Sublevel object 3:null,您的预期结果是奇怪的,因为输入中有一个sub_字段。@Andreas如果它不是字符串,它不是JSON,您可能需要澄清该语句。布尔和数字是有效的JSON实体example@customcommander是的,说JSON是字符串并不完全准确;更准确的是,JSON是包含定义良好的结构的文本。我们之所以说它是字符串,是因为在任何编程语言中使用它时,它都是字符串。对象文字表达式通常被错误地称为JSON,但因为它们不是字符串,所以实际上不是JSON。在这个问题中,对象键不是双引号,这对于JSON是必需的,但对于对象文本表达式则不是。JSON实际上是JS对象的字符串表示。非常感谢。这比我尝试的要优雅和简洁得多。证明我还有很多东西要学。我真的很感谢你抽出时间来帮忙。非常感谢。这比我尝试的要优雅和简洁得多。证明我还有很多东西要学。我真的很感谢你花时间来帮助我。有没有任何强有力的理由来解释{[name]:!sub_fields?null:Object.assign{},…sub_fields.maptransform}超过{[name]:sub_fields?Object.assign{},…sub_fields.maptransform:null}。我找到了!更难注意到。{[name]:!sub_fields?null:Object.assign{},…sub_fields.maptransform}覆盖{[name]:sub_fields?Object.assign{},…sub_fields.maptransform:null}的原因有哪些。我找到了!更难注意。如果不先合并到一个空对象中,是否会对…obj.maptransform中的第一个元素进行变异?会,但无论如何,这是一个一次性对象。如果不先合并到一个空对象中,是否会对…obj.maptransform中的第一个元素进行变异?会,但无论如何,这是一个一次性对象。