根据依赖列表排序对象数组?

时间:2018-04-17 10:05:54

标签: javascript sorting

我需要订购一个由名称和依赖列表(由名称组成)组成的对象数组。

这个数组的一个例子可能是:

[
  { name: 'a', requires: ['b', 'c'] },
  { name: 'b', requires: ['c'] },
  { name: 'c', requires: [] },
]

我希望对这个数组进行排序,以便需要一组特定依赖项的项目位于其所需的依赖项之后。
该数组实际上可以包含更多项目,如果排序函数在循环依赖的情况下抛出错误,我没关系。

示例输出:

[
  { name: 'c', requires: [] }, // first, no dependencies, and required by both the others
  { name: 'b', requires: ['c'] }, // second, because it needs `c` first
  { name: 'a', requires: ['b', 'c'] }, // last, because requires both the others
]

最简洁的方法是什么?

3 个答案:

答案 0 :(得分:8)

您可以尝试以下(更改测试用例以支持更多可能的组合)



var arr = [
  { name: 'd', requires: ['a', 'c'] },
  { name: 'a', requires: ['b', 'c'] },
  { name: 'b', requires: ['c'] },
  { name: 'e', requires: ['d'] },
  { name: 'c', requires: [] },
];

var map = {}; // Creates key value pair of name and object
var result = []; // the result array
var visited = {}; // takes a note of the traversed dependency

arr.forEach(function(obj){ // build the map
  map[obj.name]  = obj;
});

arr.forEach(function(obj){ // Traverse array
  if(!visited[obj.name]) { // check for visited object
    sort_util(obj);
  }
});

// On visiting object, check for its dependencies and visit them recursively 
function sort_util(obj){
    visited[obj.name] = true;
    obj.requires.forEach(function(dep){
        if(!visited[dep]) {
           sort_util(map[dep]);
        } 
    });
    result.push(obj);
}

console.log(result);




答案 1 :(得分:1)

更新:感谢Nina Scholz,我更新了代码,以便sort能够正常工作

这可能会起到作用。 背后的想法是,使用sort并检查元素a是否符合元素b的要求。如果是这样,我们可以假设a应该在b之前。 但我不是百分百肯定,我只是检查了你的例子和@nikhilagw的例子。我可能忘记了什么。如果有效,请告诉我!

对于每个元素,我还继承了所有依赖项。

const list = [
{ name: 'b', requires: ['c'] },
{ name: 'e', requires: ['d'] },
{ name: 'd', requires: ['a', 'c'] },
{ name: 'c', requires: [] },  
{ name: 'a', requires: ['b', 'c'] }, 
];

// indexed by name
const mapped = list.reduce((mem, i) => {
  mem[i.name] = i;
  return mem;
}, {});

// inherit all dependencies for a given name
const inherited = i => {
  return mapped[i].requires.reduce((mem, i) => {
  return [ ...mem, i, ...inherited(i) ];
  }, []);
}

// order ... 
const ordered = list.sort((a, b) => {
  return !!~inherited(b.name).indexOf(a.name) ? -1 : 1;
})

console.log(ordered);

答案 2 :(得分:0)

此提案查找以前的元素,并检查实际元素是否具有之前排序的所需要求。

如果找到所有要求,则将对象拼接到索引。

function order(array) {
    var i = 0,
        j,
        temp;

    while (i < array.length) {
        temp = array.slice(0, i);
        for (j = i; j < array.length; j++) {
            if (array[j].requires.every(n => temp.some(({ name }) => n === name))) {
                array.splice(i++, 0, array.splice(j, 1)[0]);
                break;
            }
        }
    }
    return array;
}

var array = [{ name: 'd', requires: ['a', 'c'] }, { name: 'a', requires: ['b', 'c'] }, { name: 'b', requires: ['c'] }, { name: 'e', requires: ['d'] }, { name: 'c', requires: [] }];

console.log(order(array));
.as-console-wrapper { max-height: 100% !important; top: 0; }