Javascript排序自定义比较器函数-对已排序数组进行排序

Javascript排序自定义比较器函数-对已排序数组进行排序,javascript,arrays,sorting,Javascript,Arrays,Sorting,我有一个如下形式的对象数组: arr[0] = { 'item1' : 1234, 'item2' : 'a string' }; 我首先通过'item1'对它进行排序,这很简单。现在我想再次对arr(按'item1'排序)进行排序,但这次是按'item2'进行排序,但只对'item1'相同的元素进行排序。最后一个数组如下所示: arr = [ { 'item1' : 1234, 'item2' : 'apple' }, { 'item1' : 1234, 'item2' : 'ban

我有一个如下形式的对象数组:

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;
  }
});
arr.sort(函数(a,b){
如果(a.item1==b.item1){
返回a.item2>b.item2?1:a.item2

我可以在一个函数中组合这两种排序,以获得最终的排序数组,但在某些情况下,我只能按
'item1'
'item2'
进行排序

您可以有四个不同的比较函数—一个是按项1排序,一个是按项2排序,一个是按项1排序,然后是项2排序,一个是按项2排序,然后是项1排序

例如:

arr.sort(函数(a,b){
如果(a.item1==b.item1){
返回a.item2>b.item2-1:a.item2b.item1-1:-1;
});

或者,对于第一和第二优先级排序,您可以根据需要进一步扩展它,只需用另一个比较链替换0即可。按相反顺序切换-11

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;
});
someArray.sort(函数(a,b){
返回a.item1>b.item1-1:a.item1b.item2-1:a.item2
我正在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;
  };
}

我最近问了同样的问题。他提出了一个和兰帕维尔相似的解决方案,但我更喜欢把事情一分为二。首先是一个链式比较器辅助程序,它将允许多个排序规则,每个规则在相等的情况下按顺序应用,作为平局断路器:

    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;
        };
    }
因为最初的问题是纯JavaScript,精确性:如果您不习惯使用TypeScript,只需删除键入的
:T
:((item:T)=>Comparable)即可获得普通JavaScript
到处都是,两行
都键入了。

您可以使用npm导入,然后使用来进行链接:

const comparator = queue([
    map(x => x.item1, asc),
    map(x => x.item2, asc)
]);
arr.sort(comparator);

如果您设法按item1、item2以及这两个项进行排序,那么您到底想问什么?因此,这就像编写一个装饰器模式,其中我说“new sortByItem2(new sortByItem1(arr))”。我还想像sortByItem1(arr)或sortByItem2(arr)或“new sortByItem1(new sortByItem2(arr))那样使用它,这很好,在javascript的排序函数中可以简单地使用比较器。
    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;
        };
    }
    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;
        };
    }
    arr.sort(chainedComparator(
        lambdaComparator(a => a.item1),
        lambdaComparator(a => a.item2.toLowerCase()) // "banana" before "Melon"
    ));
const comparator = queue([
    map(x => x.item1, asc),
    map(x => x.item2, asc)
]);
arr.sort(comparator);