MHo*_*gge 6 javascript arrays topological-sort
该问题已根据 @Kaddath 的好建议进行了编辑,以强调排序不必按字母顺序排列,而是取决于数组内项目的位置。
我有一个数组数组,其中每个数组都基于给定的顺序,但它们可能略有不同。
例如,基本排序是X -> D -> H -> B,这是我的数组:
const arrays = [
['X', 'D', 'H', 'B'],
['X', 'D', 'K', 'Z', 'H', 'B', 'A'],
['X', 'M', 'D', 'H', 'B'],
['X', 'H', 'T'],
['X', 'D', 'H', 'B']
]
Run Code Online (Sandbox Code Playgroud)
我想将所有数组合并为一个数组并删除重复项,但保持排序。在我的示例中,结果将是['X', 'M', 'D', 'K', 'Z', 'H', 'T', 'B', 'A'].
在示例中,我们可以看到M位于第三个数组之间X和内部,并且它被放置在最终输出中和之间。DXD
我知道可能会出现冲突,但这里有以下规则:
到目前为止我所做的是将所有这些数组合并为一个数组,方法是使用
const merged = [].concat.apply([], arrays);
Run Code Online (Sandbox Code Playgroud)
然后使用/sf/answers/110906421/中的代码片段获取唯一值:
Array.prototype.unique = function() {
var a = this.concat();
for(var i=0; i<a.length; ++i) {
for(var j=i+1; j<a.length; ++j) {
if(a[i] === a[j])
a.splice(j--, 1);
}
}
return a;
};
const finalArray = merged.unique();
Run Code Online (Sandbox Code Playgroud)
但我的结果是这样的:
[
"X",
"D",
"H",
"B",
"K",
"Z",
"A",
"M",
"T"
]
Run Code Online (Sandbox Code Playgroud)
欢迎任何帮助!
谢谢。
每个数组实际上都是一组规则,用于说明元素之间的相对顺序。最终列表应返回所有元素,同时遵守所有规则定义的相对顺序。
有些解决方案已经解决了最初的请求,有些甚至没有解决这个问题(所有建议使用排序的方法都错过了问题的要点)。然而,没有人提出通用的解决方案。
如果我们看一下OP中提出的问题,规则就是这样定义元素之间的相对位置的:
M K -> Z T
^ \ ^ \ ^
/ v/ v/
X -> D ------> H -> B -> A
Run Code Online (Sandbox Code Playgroud)
因此,很容易看出我们的数组以 X 开头。下一个元素可以是 D 和 M。但是,D 要求 M 已经在数组中。这就是为什么我们将M作为下一个元素,然后是D。接下来,D同时指向K和H。但是由于H还有一些其他的前驱元素到目前为止还没有收集到,而K没有(实际上它有D,但它已经收集在列表中),我们将放入 K 和 Z,然后才放入 H。
H同时指向T和B。实际上我们把哪一个放在前面并不重要。因此,最后三个元素可以采用以下三个顺序中的任何一个:
让我们还考虑一下更复杂的情况。规则如下:
['10', '11', '12', '1', '2'],
['11', '12', '13', '2'],
['9', '13'],
['9', '10'],
Run Code Online (Sandbox Code Playgroud)
如果我们使用这些规则绘制图表,我们将得到以下结果:
--------------> 13 ----
/ ^ \
/ / v
9 -> 10 -> 11 -> 12 > 1 -> 2
Run Code Online (Sandbox Code Playgroud)
本案有何具体情况?两件事情:
我的想法是从每个元素创建一个节点。然后使用该节点来跟踪所有直接后继者和直接前驱者。之后,我们将找到所有没有前驱的元素并开始从那里“收集”结果。如果我们到达有多个前驱的节点,但其中一些没有被收集,我们将在那里停止递归。可能会发生一些后继者已经在其他路径中收集的情况。我们会跳过那个继任者。
M K -> Z T
^ \ ^ \ ^
/ v/ v/
X -> D ------> H -> B -> A
Run Code Online (Sandbox Code Playgroud)
如果我们说n是规则的数量,m是每个规则中元素的数量,则该算法的复杂度为O(n*m)。这考虑到JS 的 Set 实现接近 O(1)。
const arrays = [
['X', 'D', 'H', 'B'],
['X', 'D', 'K', 'Z', 'H', 'B', 'A'],
['X', 'M', 'D', 'H', 'B'],
['X', 'H', 'T'],
['X', 'D', 'H', 'B']
];
const result = [];
arrays.forEach(array => {
array.forEach((item, idx) => {
// check if the item has already been added, if not, try to add
if(!~result.indexOf(item)) {
// if item is not first item, find position of his left sibling in result array
if(idx) {
const result_idx = result.indexOf(array[idx - 1]);
// add item after left sibling position
result.splice(result_idx + 1, 0, item);
return;
}
result.push(item);
}
});
});
console.log('expected result', ['X', 'M', 'D', 'K', 'Z', 'H', 'T', 'B', 'A'].join(','));
console.log(' current result',result.join(','));Run Code Online (Sandbox Code Playgroud)