我想根据“之前”和“之后”条件对数组进行排序。
示例:
should be before B
:示例:{key: 'C', condition: {$before: 'B'}
should be after A
:示例:{key: 'B', condition: {$after: 'A'}
{key: 'A'}
。生成的排序列表为:A, C, B
。
我需要这个,所以我可以在管道中对中间件列表进行排序。每个中间件都有一个条件,我应该提出一个订单,其中满足所有中间件的所有条件。这类似于MS Project
在甘特图中组织任务的情况,给出了任务的要求。
问题:实现它的最简单方法是什么?即使使用像underscore
这样的外部库?额外奖励:这种排序的名称是否比“条件排序”更好?这有助于我的Google搜索。
编辑:输入应该是具有条件的项目数组。我无法对排序方法进行硬编码。
编辑2 :正如@Berdi所述。这称为类型排序。是的,根据项目和条件,可能没有符合所有条件的组合,我的算法应该触发异常。
编辑3 :我正在考虑实现这一点的方法是计算所有可能的组合,然后寻找满足所有条件的第一个组合。这对我来说可能不是非常慢,因为在我的情况下,我只能在应用程序启动时执行此操作,并且我不会在阵列中拥有超过50个项目。但无论如何,对于科学来说,了解更优化的解决方案会更好。
编辑4 :我会接受仅在条件之后使用的解决方案。与MS Project
一样。
答案 0 :(得分:1)
奖励:这种排序的名称是否优于"条件排序"?
它被称为topological sort。根据您的确切输入格式和内容,它甚至可能没有明确定义。
答案 1 :(得分:1)
我会使用:哈希表,一个开始的指针,然后重新组装数组。
(这个答案是我对这个问题的回答的一部分:Ordering array of objects that have a BeforeID and AfterID on each object)
function chain(array) {
var o = {}, pointer;
array.forEach(function (a) {
o[a.id] = a;
if (a.beforeId === null) {
pointer = a.id;
}
});
array = [];
do {
array.push(o[pointer]);
pointer = o[pointer].afterId;
} while (pointer !== null);
return array;
}
var unsorted = [{ id: 7, beforeId: 6, afterId: 8 }, { id: 11, beforeId: 10, afterId: null }, { id: 0, beforeId: null, afterId: 1 }, { id: 1, beforeId: 0, afterId: 2 }, { id: 4, beforeId: 3, afterId: 5 }, { id: 8, beforeId: 7, afterId: 9 }, { id: 2, beforeId: 1, afterId: 3 }, { id: 9, beforeId: 8, afterId: 10 }, { id: 10, beforeId: 9, afterId: 11 }, { id: 3, beforeId: 2, afterId: 4 }, { id: 5, beforeId: 4, afterId: 6 }, { id: 6, beforeId: 5, afterId: 7 }];
document.write('<pre>' + JSON.stringify(chain(unsorted), 0, 4) + '</pre>');
编辑4 的解决方案,仅条件后的。
function chain(array) {
var n = {}, o = {}, pointer;
array.forEach(function (a) {
o[a.id] = a;
n[a.after] = a.id;
if (a.after === null) {
pointer = a.id;
}
});
// rewind pointer.
// i took push for the array. otherwise the array could be mounted
// from the other end with unshift but push is more efficient.
do {
pointer = n[pointer];
} while (pointer in n);
array = [];
do {
array.push(o[pointer]);
pointer = o[pointer].after;
} while (pointer !== null);
return array;
}
var unsorted = [{ id: 7, after: 8 }, { id: 11, after: null }, { id: 0, after: 1 }, { id: 1, after: 2 }, { id: 4, after: 5 }, { id: 8, after: 9 }, { id: 2, after: 3 }, { id: 9, after: 10 }, { id: 10, after: 11 }, { id: 3, after: 4 }, { id: 5, after: 6 }, { id: 6, after: 7 }, ];
document.write('<pre>' + JSON.stringify(chain(unsorted), 0, 4) + '</pre>');
编辑 - 在前/后稀疏
function chain(array) {
var after = {}, before = {}, o = {}, pointer = array[0].id;
array.forEach(function (a) {
o[a.id] = a;
if (a.after !== null) {
after[a.id] = a.after;
before[a.after] = a.id;
}
if (a.before !== null) {
before[a.id] = a.before;
after[a.before] = a.id;
}
});
document.write('<pre>before ' + JSON.stringify(before, 0, 4) + '</pre>');
document.write('<pre>after ' + JSON.stringify(after, 0, 4) + '</pre>');
do {
document.write('pointer: ' + pointer + '<br>');
pointer = before[pointer];
} while (pointer in before);
document.write('pointer: ' + pointer + '<br>');
array = [];
do {
array.push(o[pointer]);
pointer = after[pointer];
} while (pointer !== undefined);
return array;
}
var unsorted = [{ id: 'C', before: 'B', after: null }, { id: 'B', before: null, after: null }, { id: 'A', before: null, after: 'B' }];
document.write('<pre>' + JSON.stringify(chain(unsorted), 0, 4) + '</pre>');
答案 2 :(得分:0)
这可能有用。
function sortByRules(rules, arr) {
var rulesEvaluated = [];
rules.forEach(rule => {
applyRule(rule, arr);
rulesEvaluated.push(rule);
if (conflicts(rulesEvaluated, arr)){
throw new Error('rule conflict');
}
});
return arr;
}
function conflicts(rules, arr) {
return rules.some(r => r.condition.before ?
arr.indexOf(r.key)>arr.indexOf(r.condition.before) :
arr.indexOf(r.key)<arr.indexOf(r.condition.after));
}
function applyRule(rule, arr) {
var increment = rule.condition.before ? -1 : 1;
var item = arr.splice(arr.indexOf(rule.key), 1)[0];
var target = rule.condition.before || rule.condition.after;
arr.splice(Math.max(0, arr.indexOf(target) + increment), 0, item);
}
var toSort = ['b', 'd', 'c', 'a'];
var rules = [ { key: 'b', condition: { before: 'c' } },
{ key: 'd', condition: { after: 'c' } },
{ key: 'a', condition: { before: 'b' } } ];
document.write(sortByRules(rules, toSort)); // ['a', 'b', 'c', 'd']
&#13;
答案 3 :(得分:0)
创建一个存储所需订单的对象,然后像往常一样使用[].sort()
:
var sorter = {
'A': 1,
'B': 3,
'C': 2
}
var input = ['A', 'B', 'C'];
input = input.sort(function sort(a, b) {
return sorter[a] > sorter[b];
});
console.log(input);
document.write("<pre>" + input + "</pre>");
&#13;
现在,您可以对包含A,B和C的任意组合的任何数组进行排序。 A,B,C可以是任何东西,属性,长度,值的第一个字母......