JavaScript:如何过滤深JSON对象 [英] JavaScript: how to filter deep JSON objects

查看:90
本文介绍了JavaScript:如何过滤深JSON对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一系列深度JSON对象,看起来与此类似:

I have an array of deep JSON objects that look like similarly to this:

var hierarchy = [
  {
    "title": "category 1",
    "children": [
      {"title": "subcategory 1",
        "children": [
          {"id": 1, "title": "name 1"},
          {"id": 2, "title": "name 2"},
          {"id": 3, "title": "name 3"}
        ]
      },
      {"title": "subcategory 2",
        "children": [
          {"id": 1, "title": "name 4"}
        ]
      }
    ]
  },
  {
    "title": "category 2",
    "children": [etc. - shortened for brevity]
  }
];

所以基本上它是一个层次结构 - 有些类别可以包含子类别,其中包含具有一些ID的对象名。我还有一个与最深层次结构级别(没有子级的对象)相关的ID数组,我需要过滤这组对象,使得只包含已定义对象的(子)类别。

So basically it is a hierarchy - there are categories which can have subcategories which contain objects with some IDs and names. I also have an array of IDs that are related to the deepest hierarchy level (objects with no children) and I need to filter this set of objects in such a way that only (sub)categories that contain defined objects remain.

例如,如果我有一个包含两个ID的数组:

So for example if I had an array containing two IDs:

var IDs = [2, 3];

结果将是:

var hierarchy = [
  {
    "title": "category 1",
    "children": [
      {"title": "subcategory 1",
        "children": [
          {"id": 2, "title": "name 2"},
          {"id": 3, "title": "name 3"}
        ]
      }
    ]
  }
];

即。整体而言,整个'类别2'对象被删除,整个'子类别2'被删除,对象ID'1'被删除。

i.e. the whole, the whole 'category 2' object removed, the whole 'subcategory 2' removed, object with ID '1' removed.

问题在于深度那些对象是变量和未知的 - 有些对象没有子节点,有些对象也有子节点等,任何子类别本身都可以有子类别,我基本上需要找到没有子节点定义了ID的对象并保持整个路径对于他们每个人。

The problem is that the depth of those objects is variable and unknown - some objects have no children, some have children that also have children etc., any subcategory can can itself have a subcategory and I basically need to find object with no children that have defined IDs and keep the whole path to each of them.

谢谢。

推荐答案

基本上,执行树的深度优先遍历,在每个节点上调用回调函数。如果该节点是叶节点并且它的ID出现在列表中,则克隆导致该叶子的分支,但不重新克隆分支的任何部分已经克隆过。

Basically, perform a depth first traversal of your tree invoking a callback function on each node. If that node is a leaf node and it's ID appears in your list then clone the branch that leads to that leaf, but don't re-clone any part of the branch that was already cloned.

一旦构建了树的部分和过滤副本,就需要清理原始文件。为了记账,我在原始树中进行了突变 - 跟踪已经克隆的分支。

Once you have constructed the partial and filtered copy of your tree you need to cleanup the original. I mutated the original tree in the process for book-keeping purposes - tracking which branches had already been cloned.

编辑:修改后的代码进行过滤树木而不仅仅是一棵树

modified code to filter list of trees instead of just a single tree

var currentPath = [];

function depthFirstTraversal(o, fn) {
    currentPath.push(o);
    if(o.children) {
        for(var i = 0, len = o.children.length; i < len; i++) {
            depthFirstTraversal(o.children[i], fn);
        }
    }
    fn.call(null, o, currentPath);
    currentPath.pop();
}

function shallowCopy(o) {
    var result = {};
    for(var k in o) {
        if(o.hasOwnProperty(k)) {
            result[k] = o[k];
        }
    }
    return result;
}

function copyNode(node) {
    var n = shallowCopy(node);
    if(n.children) { n.children = []; }
    return n;
}

function filterTree(root, ids) {
    root.copied = copyNode(root); // create a copy of root
    var filteredResult = root.copied;

    depthFirstTraversal(root, function(node, branch) {
        // if this is a leaf node _and_ we are looking for its ID
        if( !node.children && ids.indexOf(node.id) !== -1 ) {
            // use the path that the depthFirstTraversal hands us that
            // leads to this leaf.  copy any part of this branch that
            // hasn't been copied, at minimum that will be this leaf
            for(var i = 0, len = branch.length; i < len; i++) {
                if(branch[i].copied) { continue; } // already copied

                branch[i].copied = copyNode(branch[i]);
                // now attach the copy to the new 'parellel' tree we are building
                branch[i-1].copied.children.push(branch[i].copied);
            }
        }
    });

    depthFirstTraversal(root, function(node, branch) {
        delete node.copied; // cleanup the mutation of the original tree
    });

    return filteredResult;
}

function filterTreeList(list, ids) {
    var filteredList = [];
    for(var i = 0, len = list.length; i < len; i++) {
        filteredList.push( filterTree(list[i], ids) );
    }
    return filteredList;
}

var hierarchy = [ /* your data here */ ];
var ids = [1,3];

var filtered = filterTreeList(hierarchy, ids);

这篇关于JavaScript:如何过滤深JSON对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆