How to sort an array of objects by multiple fields?

后端 未结 30 2359
北恋
北恋 2020-11-21 11:34

From this original question, how would I apply a sort on multiple fields?

Using this slightly adapted structure, how would I sort city (ascending) & then price (

30条回答
  •  长发绾君心
    2020-11-21 12:05

    Here's a generic multidimensional sort, allowing for reversing and/or mapping on each level.

    Written in Typescript. For Javascript, check out this JSFiddle

    The Code

    type itemMap = (n: any) => any;
    
    interface SortConfig {
      key: keyof T;
      reverse?: boolean;
      map?: itemMap;
    }
    
    export function byObjectValues(keys: ((keyof T) | SortConfig)[]): (a: T, b: T) => 0 | 1 | -1 {
      return function(a: T, b: T) {
        const firstKey: keyof T | SortConfig = keys[0];
        const isSimple = typeof firstKey === 'string';
        const key: keyof T = isSimple ? (firstKey as keyof T) : (firstKey as SortConfig).key;
        const reverse: boolean = isSimple ? false : !!(firstKey as SortConfig).reverse;
        const map: itemMap | null = isSimple ? null : (firstKey as SortConfig).map || null;
    
        const valA = map ? map(a[key]) : a[key];
        const valB = map ? map(b[key]) : b[key];
        if (valA === valB) {
          if (keys.length === 1) {
            return 0;
          }
          return byObjectValues(keys.slice(1))(a, b);
        }
        if (reverse) {
          return valA > valB ? -1 : 1;
        }
        return valA > valB ? 1 : -1;
      };
    }
    

    Usage Examples

    Sorting a people array by last name, then first name:

    interface Person {
      firstName: string;
      lastName: string;
    }
    
    people.sort(byObjectValues(['lastName','firstName']));
    

    Sort language codes by their name, not their language code (see map), then by descending version (see reverse).

    interface Language {
      code: string;
      version: number;
    }
    
    // languageCodeToName(code) is defined elsewhere in code
    
    languageCodes.sort(byObjectValues([
      {
        key: 'code',
        map(code:string) => languageCodeToName(code),
      },
      {
        key: 'version',
        reverse: true,
      }
    ]));
    

提交回复
热议问题