以递归方式将属性添加到树状结构中的每个节点,并返回修改后的树 [英] Recursively add property to every node in a tree-like structure and return modified tree

查看:165
本文介绍了以递归方式将属性添加到树状结构中的每个节点,并返回修改后的树的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于线程中的注释树,我具有以下数据结构.该结构包含在单个对象中.

I have the following data structure for a tree of comments in a thread. This structure is contained inside a single object.

comment {
    id: 1,
    text: 'foo',
    children: [
        comment {
            id: 2,
            text: 'foo-child',
            children: []
        },
        comment {
            id: 3,
            text: 'foo-child-2',
            children: []
        }
    ]
},
comment {
    id: 4,
    text: 'bar',
    children: []
}

这是由后端API提供的,这没有问题.我想做的是递归地浏览这棵树,并为每个节点(根节点或子节点)执行API调用,并每个节点获取一些额外的数据,并添加一些额外的属性,并返回整个树,并将新键添加到每个节点.

This is provided by a back-end API, there's no problem in that. What I want to do is recursively explore this tree and for each node (either root or child node) I want to perform an API call and get some extra data for every single node, slap in some extra properties, and return the entire tree with the new keys added to each node.

function expandVoteData(comments) {
    return new Promise((resolve, reject) => {
        let isAuth = Auth.isUserAuthenticated();
        // 'this' is the vote collection
        async.each(comments, (root, callback) => {
            // First get the vote data
            async.parallel({
                votedata: function(callback) {
                    axios.get('/api/comment/'+root.id+'/votes').then(votedata => {
                        callback(null, votedata.data);
                    });
                },
                uservote: function(callback) {
                    if(!isAuth) {
                        callback(null, undefined);
                    } else {
                        axios.get('/api/votes/comment/'+root.id+'/'+Auth.getToken(), { headers: Auth.getApiAuthHeader() }).then(uservote => {
                            callback(null, uservote.data); // Continue
                        });
                    }
                }
            }, function(error, data) {
                if(error) {
                    console.log('Error! ', error);
                } else {
                    // We got the uservote and the votedata for this root comment, now expand the object
                    root.canVote = isAuth;
                    root.totalVotes = data.votedata.total;
                    root.instance = 'comment';

                    if(data.uservote !== undefined) {
                        root.userVote = data.uservote;
                    }

                    if(root.children && root.children.length > 0) {
                        // Call this function again on this set of children
                        // How to "wrap up" this result into the current tree?
                        expandVoteData(root.children);
                    }
                    callback(); // Mark this iteration as complete
                }
            });
        }, () => {
            // Done iterating
            console.log(comments);
            resolve();
        });
    })
}

它的作用是:接受一个"comments"参数(它是整个树对象),创建一个Promise,遍历每个叶节点,并在异步请求中执行相应的API调用.如果叶节点有任何子节点,请对每个子节点重复该功能.

What it does is: accept a 'comments' parameter (which is the entire tree object), create a promise, iterate through each leaf node, and perform the respective API calls in asynchronous requests. If the leaf node has any children, repeat the function with each child node.

从理论上讲,这在同步世界中将是完美的,但是我要做的是将每个节点都作为单个对象进行进一步处理后,得到一棵新树,就像它作为输入一样.实际上,我为树中的每个节点获得了多个控制台打印,证明了代码在编写时就可以正常工作了……我不希望单独打印,我想将整个结果集包装在一个对象中.理想情况下,该函数应这样调用:

This theoretically would work perfectly in a synchronous world, but what I do need to do is to get the new tree after every node has been processed for further processing, as a single object, just like it was as an input. In fact, I get multiple console prints for each individual node in the tree, evidencing that the code works as it's written... I don't want individual prints though, I want to wrap up the entire set of results in a single object. Ideally, the function should be called like this:

expandVoteData(comments).then(expanded => {
    // yay!
});

有关如何执行此操作的任何提示?谢谢你.

Any tips on how to perform this? Thank you beforehand.

推荐答案

如果将代码分成多个函数并使用炫酷的async/await语法,则将变得更加容易.进一步定义一个异步功能,该功能可以更新一个节点而无需照顾子节点:

It gets more easy if you seperate the code into multiple functions and use the cool async / await syntax. Furst define an async function that updates one node without caring for the children:

async function updateNode(node) {
 const [votedata, uservote] = await Promise.all([
   axios.get('/api/comment/'+root.id+'/votes'),
    axios.get('/api/votes/comment/'+root.id+'/'+Auth.getToken(), { headers: Auth.getApiAuthHeader() })
 ]);

 node.totalVotes = votedata.total;
 node.instance = 'comment';

 if(uservote)
   node.userVote = uservote;
}

要以递归方式更新所有节点,则非常简单:

To update all nodes recursively its then as easy as:

async function updateNodeRecursively(node) {
  await updateNode(node);
  await Promise.all(node.children.map(updateNodeRecursively));
}

这篇关于以递归方式将属性添加到树状结构中的每个节点,并返回修改后的树的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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