[英]Javascript sort custom comparator function - sorting a sorted array
我有以下形式的对象数组:
arr[0] = { 'item1' : 1234, 'item2' : 'a string' };
我首先按'item1'
对它进行排序,这很简单。 现在我想再次对arr
(按'item1'
排序)进行排序,但这次按'item2'
但仅针对'item1'
相同的元素。 最终的数组看起来像:
arr = [
{ 'item1' : 1234, 'item2' : 'apple' },
{ 'item1' : 1234, 'item2' : 'banana' },
{ 'item1' : 1234, 'item2' : 'custard' },
{ 'item1' : 2156, 'item2' : 'melon' },
{ 'item1' : 4345, 'item2' : 'asparagus' }
];
我尝试为第二种情况编写一个排序函数,如下所示:
arr.sort(function(a,b){
if(a.item1 === b.item1){
return a.item2 > b.item2 ? 1 : a.item2 < b.item2 : -1 : 0;
}
});
我可以在一个函数中组合这两种排序以获得最终的排序数组,但在某些情况下,我必须仅按'item1'
或仅按'item2'
排序。
您可以使用四种不同的比较功能 - 一种按 item1 排序,一种按 item2 排序,一种按 item1 然后 item2 和一种按 item2 然后 item1。
例如:
arr.sort(function(a,b){
if(a.item1 == b.item1){
return a.item2 > b.item2 ? 1 : a.item2 < b.item2 ? -1 : 0;
}
return a.item1 > b.item1 ? 1 : -1;
});
我最近遇到了同样的问题。 提供了与 langpavel 类似的解决方案,但我更喜欢将其一分为二。 首先是一个链式比较器助手,它将允许多个排序规则,每个排序规则在相等的情况下作为决胜局应用:
type Comparator<T> = (a: T, b: T) => number; // -1 | 0 | 1
/**
* Allow to chain multiple comparators, each one called to break equality from the previous one.
*/
function chainedComparator<T>(...comparators: Comparator<T>[]): Comparator<T> {
return (a: T, b: T) => {
let order = 0;
let i = 0;
while (!order && comparators[i]) {
order = comparators[i++](a, b);
}
return order;
};
}
我喜欢它,因为它需要并返回排序比较器。 因此,如果您有其他比较器的集合,则它们很容易使用。
然后你可以通过一个额外的助手来简化你的生活。 这个基于每个项目上传递的 lambda 的结果返回一个排序比较器。
type Comparable = string | number;
/**
* Returns a comparator which use an evaluationFunc on each item for comparison
*/
function lambdaComparator<T>(evaluationFunc: ((item: T) => Comparable), reversed = false): Comparator<T> {
return (a: T, b: T) => {
const valA = evaluationFunc(a);
const valB = evaluationFunc(b);
let order = 0;
if (valA < valB) {
order = -1;
} else if (valA > valB) {
order = 1;
}
return reversed ? -order : order;
};
}
这里不需要reversed
来回答问题,但可以轻松反转顺序。
要具体回答这个问题,请使用我们的两个比较器:
arr.sort(chainedComparator(
lambdaComparator(a => a.item1),
lambdaComparator(a => a.item2.toLowerCase()) // "banana" before "Melon"
));
因为最初的问题是在纯 JavaScript 中,精度:如果你不习惯 TypeScript,你可以通过在任何地方删除<T>
, : T
, : ((item: T) => Comparable)
和两种type
行。
我在 TypeScript 中使用这个助手:
// Source
type ComparatorSelector<T> = (value: T, other: T) => number | string | null;
export function createComparator<T>(...selectors: ComparatorSelector<T>[]) {
return (a: T, b: T) => {
for (const selector of selectors) {
const valA = selector(a, b);
if (valA === null) continue;
const valB = selector(b, a);
if (valB === null || valA == valB) continue;
if (valA > valB) return 1;
if (valA < valB) return -1;
}
return 0;
};
}
// Usage:
const candidates: any[] = [];
// ...
candidates.sort(createComparator(
(x) => x.ambiguous,
(_, y) => y.refCount, // DESC
(x) => x.name.length,
(x) => x.name,
));
或者作为第一和第二优先级排序的简单单行,您可以根据需要进一步扩展它,只需将 0 替换为另一个比较链。 切换<和>或-1和1以实现相反的顺序。
someArray.sort(function(a,b) {
return a.item1 > b.item1 ? 1 : a.item1 < b.item1 ? -1 : a.item2 > b.item2 ? 1 : a.item2 < b.item2 ? -1 : 0;
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.