使用带有递归的reduce函数从多级树中生成一个扁平的id数组?

Posted

技术标签:

【中文标题】使用带有递归的reduce函数从多级树中生成一个扁平的id数组?【英文标题】:Generate a flat array of ids from a multilevel tree using reduce function with recursion? 【发布时间】:2019-07-30 13:32:16 【问题描述】:

我正在尝试使用 js 库 orgChart 实现用户层次结构。通过库中的getHierarchy() 方法正在输出如下对象。

var datascource = 
            "id": "1",
            "children": [
                "id": "2"
            , 
                "id": "3",
                "children": [
                    "id": "4"
                , 
                    "id": "5",
                    "children": [
                        "id": "6"
                    , 
                        "id": "7"
                    ]
                ]
            , 
                "id": "10"
            , 
                "id": "12"
            ]
        ;

我想从树中的 id 生成平面数组。 例如://["1", "2", "3", "4", "5", "6", "7", "10", "12"]

我想出了,

function getNestedArraysOfIds(node) 
    if (node.children == undefined) 
        return [node.id];
     else 
        return [node.id,...node.children.map(subnode => (subnode.children==undefined) ? subnode.id: getNestedArraysOfIds(subnode))];
    


function getIds(array) 
        return array.reduce((acc, subArray) =>
            (Array.isArray(subArray)) ? [...acc, ...getIds(subArray)] : [...acc, subArray]);
    

var idArrays = getNestedArraysOfIds(datascource );
var ids = getIds(idArrays); //["1", "2", "3", "4", "5", "6", "7", "10", "12"]

我尝试使用单个 reduce 函数来实现,但最终我编写了两个函数,它们都是递归的。有没有很多优雅有效的方法可以用单一的 reduce 函数来做到这一点?

提前谢谢你。

【问题讨论】:

How to flatten nested array of object using es6的可能重复 结果会是这样["1", "2", "3", "4", "5", "6", "7", "10", "12"]? @brk 是的,这就是我想要的。谢谢。 【参考方案1】:

使用Array.flatMap() 进行递归并传播以获取 id 和孩子的 id,并展平为单个数组:

const getIds = ( id, children ) => children ? [id, ...children.flatMap(getIds)] : id;

const dataSource = "id":"1","children":["id":"2","id":"3","children":["id":"4","id":"5","children":["id":"6","id":"7"]],"id":"10","id":"12"];

const result = getIds(dataSource);

console.log(result);

【讨论】:

【参考方案2】:

您可以通过使用concat 进行映射来扁平化孩子。

function getFlat( id, children = [] ) 
    return [id].concat(...children.map(getFlat));


var data =  id: "1", children: [ id: "2" ,  id: "3", children: [ id: "4" ,  id: "5", children: [ id: "6" ,  id: "7" ] ] ,  id: "10" ,  id: "12" ] ;

console.log(getFlat(data));

与reduce函数相同

function getFlat( id, children = [] ) 
    return children.reduce((r, o) => [...r, ...getFlat(o)], [id]);


var data =  id: "1", children: [ id: "2" ,  id: "3", children: [ id: "4" ,  id: "5", children: [ id: "6" ,  id: "7" ] ] ,  id: "10" ,  id: "12" ] ;

console.log(getFlat(data));

【讨论】:

【参考方案3】:

您可以创建一个简单的recursive 函数并使用for..in 对其进行迭代。如果键是id,则将它的值压入数组,否则如果键的值是数组,例如children 键的值是数组,则在 for 中调用相同的递归函数循环并传递每个对象

let datascource = 
  "id": "1",
  "children": [
    "id": "2"
  , 
    "id": "3",
    "children": [
      "id": "4"
    , 
      "id": "5",
      "children": [
        "id": "6"
      , 
        "id": "7"
      ]
    ]
  , 
    "id": "10"
  , 
    "id": "12"
  ]
;

let data = [];

function flatData(obj) 
  for (let keys in obj) 
    if (keys === 'id') 
      data.push(obj[keys])
     else if (Array.isArray(obj[keys])) 
      obj[keys].forEach((item) => 
        flatData(item)
      )

    
  

flatData(datascource)
console.log(data)

【讨论】:

以上是关于使用带有递归的reduce函数从多级树中生成一个扁平的id数组?的主要内容,如果未能解决你的问题,请参考以下文章

JAVA中生成菜单树结构常用方法总结

JAVA中生成菜单树结构常用方法总结

如何在 Clojure 中生成记忆递归函数?

C 语言多级指针 ( 在函数中生成 二级指针 | 通过传入的 三级指针 进行间接赋值 )

循环,从数组中生成带有函数的按钮

有没有办法递归地压扁元组?