如何在一个对象中找到几棵树的根

时间:2017-03-18 23:10:42

标签: javascript node.js tree

我有一系列消息,其中包含唯一的数字ID,唯一的ID和非唯一的"以回复"引用其他消息的字段。从这个目标,我试图找到所有树的根,以及与这些树相对应的所有孩子。我发现返回包含一系列节点及其相应子节点的对象相对容易,但我无法以有效的方式合并它们。不幸的是,这棵树可能有数千个深度,或只是一个层次,这使得任务变得更加困难。

let exampleTree = {
  1: {
    'ID': 'IDONE',
    'IN_REPLY_TO': undefined    
  },
  3: {
    'ID': 'IDTHREE',
    'IN_REPLY_TO': 'IDONE'
  },
  7: {
    'ID': 'IDSEVEN',
    'IN_REPLY_TO': 'IDTHREE'
  },
  8: {
    'ID': 'IDEIGHT',
    'IN_REPLY_TO': 'IDTHREE'
  }
}

// should return { 1: [3, 7, 8] }

function generateMap(tree) {
  let convert = {}
  let mapped = {}
  for (let id in tree) {
    if (typeof tree[id].IN_REPLY_TO != 'undefined') {
      if (typeof mapped[tree[id].IN_REPLY_TO] != 'undefined') {
        mapped[tree[id].IN_REPLY_TO].push(tree[id].ID)
      } else {
        mapped[tree[id].IN_REPLY_TO] = [tree[id].ID]
      }
    }
    convert[tree[id].ID] = id
  }
  let uidMapped = {}
  for (let id in mapped) {
    uidMapped[convert[id]] = mapped[id].map(function(value) { return convert[value] })
  }
  return uidMapped
}

console.log(generateMap(exampleTree))

// currently returns { 1: [3], 3: [7, 8] }

希望上面的例子清楚地说明了我想要完成的事情。七个和八个都是三个孩子,而后者又是一个孩子。我试图将这两者结合在一起。

1 个答案:

答案 0 :(得分:1)

让我们将此任务分成多个步骤并命名:

  1. 构建树
    1. 将每个message.ID与其数字id相关联。每个id对应一个树节点。
    2. 创建父节点到子节点的映射。
  2. 展平树
    1. 选择idundefined
    2. 的树根
    3. 对于每个孩子,递归地建立一个孩子所有孩子的清单。
  3. 您的generateMap计算 1。您仍然需要展平树,这可以通过递归函数轻松完成 - 请参阅下面的findAllChildren

    以下是一个示例实现。我试图评论所有步骤,并为每个涉及的实体找到有意义的名称:

    // Find all children below a given root:
    function findAllChildren(root, children) {
      let result = children[root] || [];
      for (let child of result) {
        result = result.concat(findAllChildren(child, children));
      }
      return result;
    }
    
    // Find all root messages and their children:
    function findRootAndChildMessages(messages) {
      // 1. Link each id to its respective message.ID:
      let ids = {};
      for (let [id, message] of Object.entries(messages)) {
        ids[message.ID] = id;
      }
      
      // 2. Link children to parents:
      let children = {};
      for (let [id, message] of Object.entries(messages)) {
        let parent_id = ids[message.IN_REPLY_TO];
        children[parent_id] = children[parent_id] || [];
        children[parent_id].push(id);
      }
      
      // 3. Link each child to its non-undefined root:
      let result = {};
      for (let child of children[undefined]) {
        result[child] = findAllChildren(child, children);
      }
      return result;
    }
    
    // Example:
    let messages = {
      1: {
        'ID': 'IDONE',
        'IN_REPLY_TO': undefined    
      },
      3: {
        'ID': 'IDTHREE',
        'IN_REPLY_TO': 'IDONE'
      },
      7: {
        'ID': 'IDSEVEN',
        'IN_REPLY_TO': 'IDTHREE'
      },
      8: {
        'ID': 'IDEIGHT',
        'IN_REPLY_TO': 'IDTHREE'
      }
    }
    
    console.log(findRootAndChildMessages(messages));