从嵌套数组中删除对象

5

我有一个家谱,长得像这样:

{

    "children": [{
        "name": "bob",
        "children": [{
            "name": "sam",
            "children": [{
                "name": "mike",
                "children": [{
                    "name": "elias",
                    "children": []
                }, {
                    "name": "rodriguez",
                    "children": []
                }]
            }]
        }]
    }]
}

主要的 "children" 是一个包含嵌套子数组的数组。 如何从这样一个数组中删除一个对象? 比如说我想删除名字为 "sam" 的对象,那么剩下的应该是这样的:
{
    "children": [{
        "name": "bob",
        "children": []
    }]
}

我被嵌套的问题绊住了,不知道如何开始。

欢迎提供任何帮助或指向处理类似问题的教程。


假设有许多“Sam”,您想全部删除吗? - georg
根据他的问题措辞来看,这是有歧义的——但我会说你的解决方案假设了最好的可能解释。 - aaaaaa
4个回答

11

递归是操作树形结构的好工具。

var tree = {

    "children": [{
        "name": "bob",
        "children": [{
            "name": "sam",
            "children": [{
                "name": "mike",
                "children": [{
                    "name": "elias",
                    "children": []
                }, {
                    "name": "rodriguez",
                    "children": []
                }]
            }]
        }]
    }]
}

function removeFromTree(parent, childNameToRemove){
  parent.children = parent.children
      .filter(function(child){ return child.name !== childNameToRemove})
      .map(function(child){ return removeFromTree(child, childNameToRemove)});
  return parent;
}
tree = removeFromTree(tree, 'elias')         
console.log(tree);
document.write(JSON.stringify(tree));

这篇教程看起来很有趣(“二叉树”和“图”部分)。我认为它可以帮助实现你的要求:https://www.syncano.io/blog/data-structures-in-javascript/


应该从树中删除 {"name":"rodriguez","children":[]} 吗? - guest271314
啊,{"name":"rodriguez","children":[]}"elias" 的兄弟。 - guest271314
非常感谢!感谢所有帮助过我的人。 - eggman

4

这是一个通过迭代对象并使用回溯删除给定名称的所需节点的提案。

此解决方案保留原始对象,并使用短路来防止不必要的迭代。

它也使用了递归。

function deleteFromTree(o, name) {
    function getNode(a, i) {
        if (a.name === name) {
            index = i;
            return true;
        }
        if (Array.isArray(a.children) && a.children.some(getNode)) {
            if (~index) {
                a.children.splice(index, 1);
                index = -1;
            }
            return true;
        }
    }

    var index = -1;
    [o].some(getNode);
}

var tree = { "children": [{ "name": "bob", "children": [{ "name": "sam", "children": [{ "name": "mike", "children": [{ "name": "elias", "children": [] }, { "name": "rodriguez", "children": [] }] }] }] }] };

deleteFromTree(tree, 'sam');
document.write('<pre>' + JSON.stringify(tree, 0, 4) + '</pre>');


1

The main "children" is an array containing nested child-arrays. How can I remove an object from an array like this? Lets say I want to remove the object with the name "sam", that should leave me with the following:

{
    "children": [{
        "name": "bob",
        "children": []
    }]
}
你可以利用 JSON.stringify()replacer 参数从返回的 JSON 字符串中删除属性。

replacer 可选参数
一个函数,用于改变字符串化过程的行为,或者由 String 和 Number 对象组成的数组,用作值对象中要包含在 JSON 字符串中的属性的白名单。如果这个值为 null 或未提供,则将对象的所有属性包含在生成的 JSON 字符串中。

replacer 参数

replacer 参数可以是一个函数或一个数组。作为函数时,它接受两个参数,即正在字符串化的键和值。包含该键的对象作为 replacer 函数的 this 参数提供。它最初使用表示正在字符串化的对象的空键被调用,然后为正在字符串化的对象或数组上的每个属性调用。应按以下方式返回应添加到 JSON 字符串中的值:

  • 如果返回 Number,则对应于该数字的字符串将用作将其添加到 JSON 字符串中的属性的值。

  • 如果返回 String,则该字符串将用作将其添加到 JSON 字符串中的属性的值。

  • 如果返回 Boolean,则在将其添加到 JSON 字符串中时,"true" 或 "false" 将用作属性的值,视情况而定。

  • 如果返回任何其他对象,则该对象将递归地转换为 JSON 字符串,对每个属性调用 replacer 函数,除非对象是函数,在这种情况下,不会将任何内容添加到 JSON 字符串中。

  • 如果返回 undefined,则该属性不包含在输出的 JSON 字符串中。

    注意:不能使用 replacer 函数从数组中删除值。如果返回 undefined 或函数,则使用 null 代替。


var prop = "name";
var value = "sam";
var res = JSON.stringify(data, function re(a, obj) {;
     return obj[prop] === value ? null : obj
  }, 2);

console.log(res, JSON.parse(res));

var data = {
  "children": [{
    "name": "bob",
    "children": [{
      "name": "sam",
      "children": [{
        "name": "mike",
        "children": [{
          "name": "elias",
          "children": []
        }, {
          "name": "rodriguez",
          "children": []
        }]
      }]
    }]
  }]
};

var prop = "name";
var value = "sam";
var res = JSON.stringify(data, function re(a, obj) {;
     return obj[prop] === value ? null : obj
  }, 2);

console.log(res, JSON.parse(res));

document.querySelector("pre").textContent = res;
<pre>
</pre>


我看不到任何东西(IE11) - Nina Scholz
@NinaScholz 很有趣。已经有一段时间没有尝试过ie浏览器了。在console中是否记录了任何错误?尝试在firefox、chrome/chromium浏览器中吗?在for循环内部,记录了什么在console.log(b, b[curr[prop]]) - guest271314
var curr = Object.keys(b); 翻译为:var curr = Object.keys(b); // Object.keys: 参数不是对象 - Nina Scholz
@NinaScholz 好的,这样对我们来说流程会更简单,是吗?请查看更新的帖子。 - guest271314
1
抱歉,我必须睡觉了。但现在它完美地运行了。顺便说一句,使用内置的递归迭代器是一个棘手的想法。 - Nina Scholz
显示剩余6条评论

-1
您可以使用JSON.stringify()JSON.parse()String.prototype.match()RegExp /\{"name":"sam".*(?=\]\}\]\})/来匹配具有属性"name"和值"sam"的属性,然后使用String.prototype.replace()删除字符串的其余部分,直到]}]}成为字符串的一部分。
var res = JSON.parse(
  JSON.stringify(data)
  .replace(JSON.stringify(data).match(/\{"name":"sam".*(?=\]\}\]\})/)[0]
  , ""
  , ["children"])
);

var data = {

  "children": [{
    "name": "bob",
    "children": [{
      "name": "sam",
      "children": [{
        "name": "mike",
        "children": [{
          "name": "elias",
          "children": []
        }, {
          "name": "rodriguez",
          "children": []
        }]
      }]
    }]
  }]
}

var res = JSON.parse(
  JSON.stringify(data)
  .replace(JSON.stringify(data).match(/\{"name":"sam".*(?=\]\}\]\})/)[0]
  , ""
  , ["children"])
);

console.log(data)

document.querySelector("pre").textContent = JSON.stringify(res, null, 2);
<pre>
</pre>


这正是如何不去做的典范。 - georg
@georg 是的,我知道,不过尝试一下也挺有趣的。 - guest271314
@georg,“RegExp”在“(?=]}]})”处肯定可以改进。也可以用JSON.stringify()函数替换RegExp来调整结果字符串。 - guest271314

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接