NodeJS:遍历嵌套的JSON并根据条件删除元素

时间:2019-03-27 17:25:20

标签: node.js json recursion nested iteration

假设我有一个下面的物体:

{
"schema": [
{
  "field": "name",
  "type": "String",
  "enabled": true
},
{
  "field": "age",
  "type": "Int",
  "enabled": false
},
{
  "field": "modelObj",
  "type": "object",
  "enabled": true,
  "stuff": [
    {
      "name": "mod1",
      "type": "array",
      "enabled": true
    },
    {
      "name": "mod2",
      "type": "String",
      "enabled": false
    },
    {
     "name": "mod3",
      "type": "array",
      "enabled": true
    }
  ]
},
{
  "name": "modelArr",
  "type": "array",
  "enabled": false,
  "elements": {
    "elementsType": "String"
  }
},
{
  "name": "modelsNestedArr",
  "type": "array",
  "enabled": true,
  "elements": {
    "elementsType": "object"
  },
  "stuff": [
    {
      "name": "name",
      "type": "String",
      "enabled": true
    },
    {
      "name": "models",
      "type": "array",
      "enabled": false,
      "elements": {
        "elementsType": "String"
      }
    }
  ]
  }
  ]
  }

我要递归地遍历此对象,并根据“ enabled”是否为false删除该项目。

所以预期的输出是:

[
{
  "field": "name",
  "type": "String",
  "enabled": true
},
{
  "field": "modelObj",
  "type": "object",
  "enabled": true,
  "stuff": [
    {
      "name": "mod1",
      "type": "array",
      "enabled": true
    },
    {
     "name": "mod3",
      "type": "array",
      "enabled": true
    }
  ]
},
{
  "name": "modelsNestedArr",
  "type": "array",
  "enabled": true,
  "elements": {
    "elementsType": "object"
  },
  "stuff": [
    {
      "name": "name",
      "type": "String",
      "enabled": true
    }
  ]
  }
 ]

我写了如下代码:

function r(a){
     for (i = a.length - 1; i >= 0; --i) {
        if(!a[i].enabled){
         a.splice(i,1)
        } else if (a[i].enabled){
            if(a[i].type == "object"){
              if(a[i]){
                a[i].stuff= r(a[i].stuff)
              }
        } else if (a[i].type == "array"){
            if(a[i].hasOwnProperty("elements") && a[i].elements.elementsType== "object"){
               a[i].stuff= r(a[i].stuff)
           }
        } 
      }
    }

    return a
    }

    var final = r(a.schema)
    console.log(JSON.stringify(final))

但是,我得到以下输出:

错误输出:

[
{
"field": "name",
"type": "String",
"enabled": true
},
{
"field": "age",
"type": "Int",
"enabled": false
},
{
"field": "modelObj",
"type": "object",
"enabled": true,
"stuff": [
  {
    "name": "mod1",
    "type": "array",
    "enabled": true
  },
  {
    "name": "mod2",
    "type": "String",
    "enabled": false
  },
  {
    "name": "mod3",
    "type": "array",
    "enabled": true
  }
]
},
{
"name": "modelArr",
"type": "array",
"enabled": false,
"elements": {
  "elementsType": "String"
}
},
{
"name": "modelsNestedArr",
"type": "array",
"enabled": true,
"elements": {
  "elementsType": "object"
},
"stuff": [
  {
    "name": "name",
    "type": "String",
    "enabled": true
  }
]
}
]

我到底在做错什么吗?

4 个答案:

答案 0 :(得分:2)

使用.map()和.filter()的递归函数将使您的生活更轻松:

import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';

void main() => runApp(SnackBarDemo());

class SnackBarDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
     title: 'SnackBar Demo',
     home: CupertinoPageScaffold(
    child: SnackBarPage(),
       ),
     );
   }
 }

class SnackBarPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
   body: SnackBarBody(),
   );
 }
}

class SnackBarBody extends StatefulWidget {
  SnackBarBody({Key key,}):
      super(key: key);

  @override
  _SnackBarBodyState createState() => new _SnackBarBodyState();
}

class _SnackBarBodyState extends State<SnackBarBody> {

@override
Widget build(BuildContext context) {
  return Center(
    child: RaisedButton(
      onPressed: () {
        final snackBar = SnackBar(content: Text('Yay! A SnackBar!'),action: SnackBarAction(label: 'Undo',
          onPressed: () {
            // Some code to undo the change!
          },
        ),
      );

        // Find the Scaffold in the Widget tree and use it to show a SnackBar!
        Scaffold.of(context).showSnackBar(snackBar);
       },
      child: Text('Show SnackBar'),
     ),
   );
  }
}

这将适用于任何深度。

它确实假定您的所有数组都在 function isEnabledRecursive(data){ return data.filter( item=>item.enabled ) .map( item=>item.stuff?Object.assign(item,{stuff:isEnabledRecursive(item.stuff)}) :item ); } const dataWithFilteredSchema = Object.assign(data, {schema:isEnabledRecursive(data.schema)}) 属性中。如果您有其他带有对象数组的属性,则必须使用stuff之类的属性遍历每个属性,以查看它们中是否包含数组。

至于为什么您的原始代码无法正常工作,如果语句正在运行,您的其他代码就什么也没有。当您说for(property of item)a[i].type时,它是未定义的。您可能想说a[i].dataTypetypeof a[i] === "object"

答案 1 :(得分:1)

根据我的观察,您的架构对象不一致或函数。 您的架构对象具有 type dataType 键。我正在考虑将其全部视为类型,这是解决方案。

在您的splice实现中,数组在循环中发生了变化,可能会跳过一些索引。

例如如果数组是

[
  {name: 'mod1', enabled: false},
  {name: 'mod2', enabled: true},
  {name: 'mod3', enabled: true}
]

删除索引0后,数组长度变为2而不是3。因此,将少访问一个元素。

因此,我包含了另一个对象 deleteIndices ,以在循环完成后标记要删除的索引。

  

顺便说一句,您始终可以选择地图过滤器以这种方式   更简单。

function r(a) {
  let deleteIndices = {};
  for (let i = 0; i < a.length; i++) {
    if (!a[i].enabled) {
      deleteIndices[i] = true;
    } else {
      if (a[i].type == "object") {
        a[i].stuff = r(a[i].stuff)
      } else if (a[i].type == "array" && a[i].elements && a[i].elements.elementsType == "object") {
        a[i].stuff = r(a[i].stuff)
      }
    }
  }

  a = a.filter((e, index) => !deleteIndices[index])
  return a;
}

schema = r(schema)

答案 2 :(得分:0)

让我们以 a 的名称命名您的数组(object.schema),然后可以像这样获得结果:

var result = a.filter(element => element.enabled).map(element => {
  if ((element.dataType == "object" || element.type == "array") && element.stuff && element.stuff.length > 0) {
    element.stuff = element.stuff.filter(st => st.enabled);
  }

  return element;
});

请注意,有时您有dataType,有时您有类型作为字段名称。

您应该使用地图过滤器。 编写和使用非常简单。

文档:mapfilter

答案 3 :(得分:0)

我能想到的最简单,最贴心的解决方案,它将在任何深度都适用

function r(arr){
  let filtered =  arr.filter((obj)=>{
    return obj.enabled;
  });
  return filtered.map((obj)=>{
    if(obj.stuff)
      obj.stuff = r(obj.stuff)
    return obj
  })
}
result = r(a.schema)
console.log(JSON.stringify(result,null,2))