5

我有一个需要找出依赖关系的元素列表。

我有:

[{
  "a": ["b", "d"]
}, {
  "d": ["c", "e"]
}]

a取决于bd,并且d取决于ce。有没有办法为此巧妙地构建依赖关系?输出应该(可能)是:

["b", "c", "e", "d", "a"]

/克里斯蒂安

4

1 回答 1

7

假设您想要一个元素的递归依赖项列表,包括元素本身,以任何顺序:

“对于每个依赖项,将其依赖项添加到依赖项列表中”足够聪明吗?

function recursiveDependencies (dependencies, element){
  var output = [element];
  for(i=0; i<output.length(); i++){
    dependencies[output[i]].forEach(function(x){
      if(output.indexOf(x)<0){ //prevent duplicates
        output.push(x)
      }
    })
  }
  return output;
}

如果您希望元素本身位于末尾而不是开头,您可以使用output.push(output.shift())


如果您希望您的依赖项的顺序是每个元素都在依赖它的元素之前,那么您必须定义如何处理循环依赖项。一种处理方法是检测循环依赖并失败。

如果最多一个元素需要每个依赖项,那么您可以使用前面的算法:只需向后读取输出(或反转数组或使用unshift代替push(警告:性能下降))


依赖关系形成一个图,您正在寻找它的拓扑排序。一种(低效)方法是以深度优先顺序对节点进行排序,并在重新输入时重新插入它们。您可以使用 Open 堆栈来检测错误 - 如果子项从其父项重新进入,则您有一个循环依赖项。

更好的解决方案是使用标准的拓扑排序算法:虽然有未排序的节点,但选择一个没有未解决的依赖关系的节点:

function recursiveDependencies (dependencies, root){
  var nodes={};
  var nodeCount=0;
  var ready=[];
  var output=[];

  // build the graph
  function add(element){
     nodeCount++;
     nodes[element]={needs:[], neededBy:[], name: element};
     if(dependencies[element]){
       dependencies[element].forEach(function(dependency){
         if(!nodes[dependency]) add(dependency);
         nodes[element].needs.push(nodes[dependency]);
         nodes[dependency].neededBy.push(nodes[element]);
       });
     }
     if(!nodes[element].needs.length) ready.push(nodes[element]);
  }

  if(root){
    add(root)
  } else {
     for (element in dependencies){
       if(!nodes[element]) add(element);
    }
  }


  //sort the graph
  while(ready.length){
    var dependency = ready.pop();
    output.push(dependency.name);
    dependency.neededBy.forEach(function(element){
      element.needs = element.needs.filter(function(x){return x!=dependency})
      if(!element.needs.length) ready.push(element)
    })
  }

  //error-check
  if(output.length != nodeCount){
    throw "circular dependency detected"
  }

  return output;
}

小提琴:http: //jsfiddle.net/Xq5dz/4/

于 2012-11-09T06:28:44.313 回答