在 javascript 中递归压缩数组对象

condensing the array object recursively in javascript

我有一个对象数组,格式如下:

{
  "country": "India",
  "children": [
    {
      "name": "Karnataka",
      "type": "State",
      "children": [
        {
          "name": "",
          "type": "city"
        },
        {
          "name": "Bangalore",
          "type": "city"
        },
        {
          "name": "Mangalore",
          "type": "city"
        }
      ]
    },
    {
      "name": "Kerala",
      "type": "State",
      "children": [
        {
          "name": "",
          "type": "city"
        }
      ]
    },
    {
      "name": "Maharashtra",
      "type": "State",
      "children": [
        {
          "name": "Mumbai",
          "type": "city"
        },
        {
          "name": "Pune",
          "type": "city"
        }
      ]
    }
  ]
}

每个对象都有一个包含元素详细信息的子元素。我需要递归遍历 json 对象并删除所有 name 为空字符串的节点,直到根。对于上述 json 格式,输出应如下所示:

{
  "country": "India",
  "children": [
    {
      "name": "Karnataka",
      "type": "State",
      "children": [
        {
          "name": "Bangalore",
          "type": "city"
        },
        {
          "name": "Mangalore",
          "type": "city"
        }
      ]
    },
    {
      "name": "Kerala",
      "type": "State",
      "children": [
      ]
    },
    {
      "name": "Maharastra",
      "type": "State",
      "children": [
        {
          "name": "Mumbai",
          "type": "city"
        },
        {
          "name": "Pune",
          "type": "city"
        }
      ]
    }
  ]
}

如何在 javascript 中使用 Underscorejs 递归执行此操作。

试试这个:

function condense(arr) {

  arr.children = arr.children.map(function(c) {
    c.children = c.children.filter(function(c1) {
      return c1.name;
    });
    return c;
  });

  return arr;
}

我遍历子项(使用 map),然后使用 filter 过滤子项数组。仅保留名称不为 null 或为空的子项。

这里是jsfiddle.

不符合 underscore.js。您可以使用 ES5 reduceRight 执行此操作并删除您不需要的成员,它应该比其他方法更有效。以下使用递归(它不如串行处理高效,但可能代码更少),因此您可以根据需要嵌套对象:

function removeEmpty(obj) {
  obj.children.reduceRight(function (acc, child, i) {
    if (!child.name) {
      obj.children.splice(i, 1);
    } else if (child.children) {
      removeEmpty(child);
    }
    return null;
  }, null);
  return obj;
}

// Test
var data = {
  "country": "India",
  "children": [
    {
      "name": "Karnataka",
      "type": "State",
      "children": [
        {
          "name": "",
          "type": "city"
        },
        {
          "name": "Bangalore",
          "type": "city"
        },
        {
          "name": "Mangalore",
          "type": "city"
        }
      ]
    },
    {
      "name": "Kerala",
      "type": "State",
      "children": [
        {
          "name": "",
          "type": "city"
        }
      ]
    },
    {
      "name": "Maharashtra",
      "type": "State",
      "children": [
        {
          "name": "Mumbai",
          "type": "city"
        },
        {
          "name": "Pune",
          "type": "city"
        }
      ]
    }
  ]
}


document.write('Original:<br>' + JSON.stringify(data) + '<br><br>' +
               'Modified:<br>' + JSON.stringify(removeEmpty(data)));

这是一个 Array#filter() 的递归解决方案。

function filterName(a) {
    if (a.name) {
        if (Array.isArray(a.children)) {
            a.children = a.children.filter(filterName);
        }
        return true;
    }
}

var object = { "country": "India", "children": [{ "name": "Karnataka", "type": "State", "children": [{ "name": "", "type": "city" }, { "name": "Bangalore", "type": "city" }, { "name": "Mangalore", "type": "city" }] }, { "name": "Kerala", "type": "State", "children": [{ "name": "", "type": "city" }] }, { "name": "Maharashtra", "type": "State", "children": [{ "name": "Mumbai", "type": "city" }, { "name": "Pune", "type": "city" }] }] };

object.children.forEach(filterName);
document.write("<pre>" + JSON.stringify(object, 0, 4) + "</pre>");

这非常适合您的示例。

Link to fiddle

var obj = {
  "country": "India",
  "children": [{
    "name": "Karnataka",
    "type": "State",
    "children": [{
      "name": "",
      "type": "city"
    }, {
      "name": "Bangalore",
      "type": "city"
    }, {
      "name": "Mangalore",
      "type": "city"
    }]
  }, {
    "name": "Kerala",
    "type": "State",
    "children": [{
      "name": "",
      "type": "city"
    }]
  }, {
    "name": "Maharashtra",
    "type": "State",
    "children": [{
      "name": "Mumbai",
      "type": "city"
    }, {
      "name": "Pune",
      "type": "city"
    }]
  }]
};

//Before
document.write("BEFORE: "+JSON.stringify(obj));
//After
document.write("AFTER: "+JSON.stringify(checkJSON(obj)));

function checkJSON(obj) {
  $.each(obj.children, function(index, value) {
    if ($.isArray(value.children)) {
      $.each(value.children, function(index, value) {
        if (value.name == '') {
          delete value.name;
        }
      });
    }
  });
  return obj;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

可能不是最短的方法,但它有效:

obj.children = _.each(obj.children, filter);

function filter(child, index, arr) {
  if (child && child.name === '') {
    // remove the ones without name
    arr.splice(index, 1);

  } else if (_.has(child, 'children')) {
    // remove nested children
    child.children = _.each(child.children, filter);

    // check for empty children array and remove it (if needed)
    /*
    if (child.children.length === 0) {
      delete child['children'];
    }
    */
  }

  return child;
}

Fiddle: https://jsfiddle.net/gnmosu5p/2/

我知道有人要求递归方法,但我忍不住在这里给出一个衬垫。

var newData = JSON.parse(JSON.stringify(data).replace(/{"name":"".+?},?/g, ""));

其中 data 是最初给定的要重构的对象。

它比数组函数慢一些,但此方法的一个优点是保留原始数据对象,而所有数组方法将覆盖原始数据对象,除非您克隆它。