在javascript中递归地压缩数组对象

时间:2016-04-06 06:43:39

标签: javascript arrays underscore.js javascript-objects

我有以下格式的对象数组:

{
  "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"
        }
      ]
    }
  ]
}

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

6 个答案:

答案 0 :(得分:3)

这是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>");

答案 1 :(得分:1)

试试这个:

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

答案 2 :(得分:1)

使用underscore.js

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

&#13;
&#13;
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)));
&#13;
&#13;
&#13;

答案 3 :(得分:1)

这是非常具体的例子。

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>

答案 4 :(得分:1)

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

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

小提琴:https://jsfiddle.net/gnmosu5p/2/

答案 5 :(得分:1)

我知道有一种递归的方法,但我不能帮助自己在这里提供一个班轮。

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

其中data是最初要重组的对象。

它比数组函数稍慢,但这种方法的一个优点是保留了原始数据对象,而所有数组方法都将覆盖原始数据对象,除非你克隆它。