我有一系列颜色,我想按顺序排序。但是,我不想使用他们的"自然"订购,而是按顺序保留它们:
var order = ['white', 'yellow', 'violet', 'blue', 'orange', 'red', 'maroon', 'brown', 'black'];
因此,例如,对此数组进行排序
var items = ['blue', 'violet', 'white', 'black', 'orange'];
应该回馈
['white', 'violet', 'blue', 'orange', 'black'];
这是我到目前为止所拥有的:
var itemsInOrder = [];
for (var i=0; i<order.length; i++) {
if (items.indexOf(order[i]) > -1) {
itemsInOrder.push(order[i]);
}
}
我不确定它的扩展程度 - 如果order
有100或1000个元素,但&#39;项目&#39;有10个?
实现这一目标的好方法是什么?
答案 0 :(得分:7)
正如@Shmiddty在评论中指出的,一种简单的方法是使用库sort
函数和自定义比较器,如下所示:
items.sort(function(a,b) {
return order.indexOf(a) - order.indexOf(b);
});
我从那开始。如果它足够快,太棒了!跟着它。
从时间复杂度的角度来看,让我们假设你有一个要排序的n个元素的列表,主排序中有k个元素。然后使用自定义比较器调用sort
将进行O(n log n)比较,由于扫描列表的成本,每个比较需要时间O(k)。这给出了O(kn log n)的运行时间。假设k很小 - 也就是说,你的主列表不会太长 - 这非常好。
如果k很大 - 例如,如果你对世界上所有城市都有固定的排序,或类似的东西 - 那么这种方法不太可能很好地扩展。在这种情况下,您可能希望通过创建直接映射要排序到其索引的所有内容的字典来为问题添加另一层间接。这是一种方法:
var indexMap = {};
for (var i = 0; i < order.length; i++) {
indexMap[order[i]] = i;
}
items.sort(function(a,b) {
return indexMap[a] - indexMap[b];
});
这具有时间复杂度O(k + n log n),因此对于非常大的k,它可能会明显更快。
答案 1 :(得分:0)
除了templatetypedef的答案外,还有一件事是,如果您的预定义是“部分的”,例如列表中的某些项目无法按照您的预定义顺序进行排序,那么您可以将这些项目从列表中分离出来,然后将它们重新连接到列表的末尾,例如
var items = [3, 2, 3, 2, 1, 4, 5, 1, 2, 3]
var order = [1, 2, 3]
var unordered = items.filter(t => order.indexOf(t) === -1);
var ordered = items.filter(t => order.indexOf(t) !== -1);
ordered.sort(function(a,b) {
return order.indexOf(a) - order.indexOf(b);
});
var final = ordered.concat(unordered)
console.log(final)
// [ 1, 1, 2, 2, 2, 3, 3, 3, 4, 5 ]
如果您不执行此步骤,则排序实际上会将无序项目放在列表的最前面,我不知道如何更改它以将其移回末尾而不过滤掉它们首先。
答案 2 :(得分:0)
如果有人正在寻找比Colin D更简单的代码来对数组进行排序并在末尾添加未知项,这是另一个示例:
let list = ["A", "F", "Banana", "rules", "L", "Juice", "Z"]
let order = ["Banana", "Juice", "rules"]
list.sort((a, b) => {
if (order.indexOf(a) === -1) return 1
if (order.indexOf(b) === -1) return -1
return order.indexOf(a) - order.indexOf(b)
})
console.log(list)
这将记录:["Banana", "Juice", "rules", "A", "F", "L", "Z"]