简体   繁体   English

在嵌套子节点的数组树中找到最高的 object

[英]Find the highest object in array tree of nested children

I have an array of nested regions that look like this:我有一组嵌套区域,如下所示:

  • Egypt埃及
    • Zone 1 1区
      • Tagamo3多加莫3
      • Giza吉萨
      • Helwan赫勒万
      • Fayoum法尤姆
    • Zone 2 2区
      • Gesr ElSuis Gesr ElSuis
        • test测试
      • Delta三角洲
      • Mohandeseen莫汉德森
      • Down Town市中心

The array itself:数组本身:

[
  {
    "key": 10,
    "title": "Egypt",
    "parent_key": null,
    "children": [
      {
        "key": 1,
        "title": "Zone 1",
        "parent_key": 10,
        "children": [
          {
            "key": 3,
            "title": "Tagamo3",
            "parent_key": 1,
            "children": []
          },
          {
            "key": 7,
            "title": "Giza",
            "parent_key": 1,
            "children": []
          },
          {
            "key": 8,
            "title": "Helwan",
            "parent_key": 1,
            "children": []
          },
          {
            "key": 11,
            "title": "Fayoum",
            "parent_key": 1,
            "children": []
          }
        ]
      },
      {
        "key": 2,
        "title": "Zone 2",
        "parent_key": 10,
        "children": [
          {
            "key": 4,
            "title": "Gesr ElSuis",
            "parent_key": 2,
            "children": [
              {
                "key": 12,
                "title": "test",
                "parent_key": 4,
                "children": []
              }
            ]
          },
          {
            "key": 5,
            "title": "Delta",
            "parent_key": 2,
            "children": []
          },
          {
            "key": 6,
            "title": "Mohandeseen",
            "parent_key": 2,
            "children": []
          },
          {
            "key": 9,
            "title": "Down Town",
            "parent_key": 2,
            "children": []
          }
        ]
      }
    ]
  }
]

I want to return to the highest region in a given input我想返回给定输入中的最高区域

Examples:例子:

  • input [7, 1, 10] should return [10] since 10 is Egypt parent of 1 and 7输入 [7, 1, 10] 应该返回 [10] 因为 10 是 1 和 7 的埃及父级
  • input [1, 2] should return both [1, 2] since they are on the same level both Zone 1 and zone 2 located under Egypt输入 [1, 2] 应该返回两个 [1, 2] 因为它们位于埃及下的区域 1区域 2的同一级别
  • input [2, 3, 1] should return [2, 1] since they are on the same level and 3 removed because it's a child of 1输入 [2, 3, 1] 应该返回 [2, 1] 因为它们在同一级别上,并且 3 因为它是 1 的子级而被删除
  • input [1, 4] should return [1, 4] since they are on different levels and no one parent to the other输入 [1, 4] 应该返回 [1, 4] 因为它们处于不同的级别并且没有一个父级到另一个

First it helps to turn your tree structure into a map of descendant ids, recursively:首先,它有助于将您的树结构递归地转换为后代 id 的 map:

const descendantsMap = new Map<number, Set<number>>();
function walk(tree: Tree) {
  const s: Set<number> = new Set();
  descendantsMap.set(tree.key, s);
  for (const t of tree.children) {
    walk(t);
    s.add(t.key);
    descendantsMap.get(t.key)?.forEach(v => s.add(v));
  }
}
arr.forEach(walk);

We are building up a Map from each key in your tree structure to a Set of the key s of its descendants.我们正在构建一个Map从树结构中的每个key到其后代的Set key The walk() function is recursive, and we merge the descendants for the children of each node into the descendants for the current node. walk() function 是递归的,我们将每个节点的children节点的后代合并到当前节点的后代中。

Let's make sure it looks right:让我们确保它看起来正确:

console.log(descendantsMap);
/* Map (12) {
    10 => Set (11) {1, 3, 7, 8, 11, 2, 4, 12, 5, 6, 9}, 
    1 => Set (4) {3, 7, 8, 11}, 
    3 => Set (0) {}, 
    7 => Set (0) {}, 
    8 => Set (0) {}, 
    11 => Set (0) {}, 
    2 => Set (5) {4, 12, 5, 6, 9}, 
    4 => Set (1) {12}, 
    12 => Set (0) {}, 
    5 => Set (0) {}, 
    6 => Set (0) {}, 
    9 => Set (0) {}
} */

Yes.是的。 You can see how now we have a quick mapping from each key to the set of key s in its descendant subtree.您可以看到现在我们如何快速映射从每个key到其后代子树中的key集。


Now to get the "highest" entries in an array (I would call these the "shallowest" since they are closest to the root), we find all the descendants of all the elements in the array and then filter these out of the array:现在要获取数组中的“最高”条目(我将它们称为“最浅”,因为它们最接近根),我们找到数组中所有元素的所有后代,然后将它们从数组中过滤掉:

const shallowest = (x: number[]): number[] => {
  const descendants = new Set<number>();
  for (const v of x) {
    descendantsMap.get(v)?.forEach(i => descendants.add(i));
  }
  console.log(descendants); // just to understand what's happening
  return x.filter(v => !descendants.has(v));
}

Let's test it:让我们测试一下:

console.log(shallowest([7, 1, 10])); 
// descendants are {3, 7, 8, 11, 1, 2, 4, 12, 5, 6, 9} 
// output [10]

console.log(shallowest([1, 2])); 
// descendants are {3, 7, 8, 11, 4, 12, 5, 6, 9};
// output [1, 2]

console.log(shallowest([2, 3, 1])); 
// descendants are {4, 12, 5, 6, 9, 3, 7, 8, 11};
// output [2, 1]

console.log(shallowest([1, 4])); 
// descendants are {3, 7, 8, 11, 12};
// output [1, 4]

Looks good.看起来不错。 You can see that shallowest([7, 1, 10]) first finds all the descendants of 7 , 1 , and 10 , which is {3, 7, 8, 11, 1, 2, 4, 12, 5, 6, 9} , or everything except 10 .可以看到shallowest([7, 1, 10])首先找到了7 , 1 , 10的所有后代,即{3, 7, 8, 11, 1, 2, 4, 12, 5, 6, 9} ,或10之外的所有内容。 So when we filter those out of [7, 1, 10] we are left with just 10 .因此,当我们从[7, 1, 10]中过滤掉那些时,我们只剩下10了。 Similarly, shallowest([1, 2]) and shallowest([1, 4]) produce sets of descendants that don't overlap at all with the input, so the output is identical to the input.类似地, shallowest([1, 2])shallowest([1, 4])产生与输入完全不重叠的后代集,因此 output 与输入相同。 And with shallowest([2, 3, 1]) , the list of descendants contains 3 but not 2 or 1 , so the output is [2, 1] .并且使用shallowest([2, 3, 1]) ,后代列表包含3但不包含21 ,因此 output 是[2, 1]

Playground link to code Playground 代码链接

This is my 2nd attempt, thanks to jcalz for pointing out the error and his solution is neater than mine.这是我的第二次尝试,感谢 jcalz 指出错误,他的解决方案比我的更整洁。

The function buildArray builds an array of objects in to the variable keyArray, the key is the element in the array to be searched and another array that's the path to that element (so key 7 will have a path of [10, 1, 7]). function buildArray 在变量 keyArray 中构建了一个对象数组,键是要搜索的数组中的元素,另一个数组是该元素的路径(因此键 7 的路径为 [10, 1, 7] )。

We then filter keyArray to remove any elements that have a parent in the original search array.然后我们过滤 keyArray 以删除在原始搜索数组中具有父元素的任何元素。

Anyway, reading jcalz's solution, I've learnt about maps so my time's not been entirely wasted.无论如何,阅读 jcalz 的解决方案,我已经了解了地图,所以我的时间并没有完全浪费。 Hope this helps in some way though.希望这在某种程度上有所帮助。

console.log(search2([7, 1, 10], obj));  //returns [10]
console.log(search2([1,2], obj));       //returns [1,2]
console.log(search2([2,3,1], obj));     //returns [1,2]
console.log(search2([1,4], obj));       //returns [1,4]

function search2(search, obj) {
  keyArray=[];
  buildArray(obj);
  return keyArray.filter((element)=> !element.path.some(e => search.includes(e))).map((e)=> e.key);
  
  function buildArray(obj, path=[]) {
    obj.forEach((element) =>{
      if(search.includes(element.key)) {
        keyArray.push({"key":element.key,"path":path});
      }
      buildArray(element.children,[...path,element.key]);
    });
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM