【问题标题】:condensing the array object recursively in javascript在javascript中递归地压缩数组对象
【发布时间】:2016-07-26 09:38:46
【问题描述】:

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

{
  "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 中递归执行此操作。

【问题讨论】:

  • @RayonDabre—在我看来 reduceRight 和删除不需要的成员更好,但是 underscore.js 有吗?如果没有,那就是内置的。
  • This SO question 可能会帮助你
  • 我不知道保留原始数据对象对您来说有多重要,但是如果您采用数组函数的方式,您可能会丢失它,除非您首先通过某种方式克隆该对象。

标签: javascript arrays underscore.js javascript-objects


【解决方案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】:

not au fait with 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)));

【讨论】:

  • 哦,reduceRight 的用法在这里很混乱,因为你没有减少任何东西......
  • 是的,只是从length迭代到0,累加器被忽略。也许应该有一个forEachRight? ;-) 现在想想,return null 可以省略。
  • 也可能是_ 而不是acc
【解决方案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>");

【讨论】:

    【解决方案4】:

    这对您的示例非常具体。

    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;
    }
    &lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"&gt;&lt;/script&gt;

    【讨论】:

      【解决方案5】:

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

      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/

      【讨论】:

        【解决方案6】:

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

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

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

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

        【讨论】:

          猜你喜欢
          • 2019-12-31
          • 2018-04-20
          • 2020-08-04
          • 1970-01-01
          • 2011-09-05
          • 2020-04-24
          • 1970-01-01
          • 2016-08-16
          • 1970-01-01
          相关资源
          最近更新 更多