繁体   English   中英

给定预定义顺序对字符串列表进行排序

[英]Sort a list of strings given a predefined order

我有一系列要按顺序排序的颜色。 但是,我不想使用它们的“自然”顺序对它们进行排序,而是按照以下顺序对它们进行排序:

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 个元素但“项目”有 10 个怎么办?

有什么好的、可扩展的方式来实现这一点?

正如@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,它可能会明显更快。

除了 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 ]

如果你不采取这一步,那么排序实际上会将无序的项目放在列表的前面,我不知道如何更改它以将它们移回末尾而不先将它们过滤掉。

如果有人正在寻找比 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"]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM