【问题标题】:Javascript sort custom comparator function - sorting a sorted arrayJavascript排序自定义比较器功能 - 排序排序数组
【发布时间】:2011-11-01 17:21:57
【问题描述】:

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

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 和这两个排序,那么您到底在问什么?
  • 所以这就像写一个装饰器模式,我说“new sortByItem2(new sortByItem1(arr))”。我也想像 sortByItem1(arr) 或 sortByItem2(arr) 或 "new sortByItem1(new sortByItem2(arr))" 那样使用它

标签: javascript arrays sorting


【解决方案1】:

您可以使用四种不同的比较函数 - 一种按 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;
});

【讨论】:

  • 在 javascript 的排序函数中使用比较器非常简单。
【解决方案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 (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,你可以通过删除打字 &lt;T&gt;: T: ((item: T) =&gt; Comparable) 和两个 @987654328 来获得普通的 JavaScript @ 换行。

【讨论】:

  • scoreA 应该是 lambdaComparator 中的 valAB 类似。
【解决方案3】:

我在 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,
));

【讨论】:

    【解决方案4】:

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

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

    【讨论】:

      【解决方案5】:

      或者作为第一和第二优先级排序的简单单线,您可以根据需要进一步扩展它,只需将 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;
      });
      

      【讨论】:

        猜你喜欢
        • 2022-01-05
        • 1970-01-01
        • 1970-01-01
        • 2013-11-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多