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

时间:2011-08-23 07:27:38

标签: javascript arrays sorting

我有以下形式的对象数组:

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'排序。

5 个答案:

答案 0 :(得分:28)

你可以有四种不同的比较功能 - 一种按item1排序,一种按item2排序,一种按item1然后按item2,一种按item2然后按item1。

E.g:

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;
});

答案 1 :(得分:2)

我最近遇到了同样的问题。提供了与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 (scoreA < scoreB) {
                order = -1;
            } else if (scoreA > scoreB) {
                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)就可以得到普通的JavaScript。随处可见,并且有两个type行。

答案 2 :(得分:1)

您可以使用npm导入type-comparator,然后使用queue进行链接:

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

答案 3 :(得分:0)

或者作为第一和第二优先级排序的简单oneliner,您可以根据需要进一步扩展它,只需将0替换为另一个比较链。为逆转订单切换&lt; &gt; -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;
});

答案 4 :(得分:0)

我在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;
  };
}