How to sort an array of objects by multiple fields?

后端 未结 30 2309
北恋
北恋 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:02

    for a non-generic, simple solution to your exact problem:

    homes.sort(
       function(a, b) {          
          if (a.city === b.city) {
             // Price is only important when cities are the same
             return b.price - a.price;
          }
          return a.city > b.city ? 1 : -1;
       });
    
    0 讨论(0)
  • 2020-11-21 12:03

    Wow, there are some complex solutions here. So complex I decided to come up with something simpler but also quite powerful. Here it is;

    function sortByPriority(data, priorities) {
      if (priorities.length == 0) {
        return data;
      }
    
      const nextPriority = priorities[0];
      const remainingPriorities = priorities.slice(1);
    
      const matched = data.filter(item => item.hasOwnProperty(nextPriority));
      const remainingData = data.filter(item => !item.hasOwnProperty(nextPriority));
    
      return sortByPriority(matched, remainingPriorities)
        .sort((a, b) => (a[nextPriority] > b[nextPriority]) ? 1 : -1)
        .concat(sortByPriority(remainingData, remainingPriorities));
    }
    

    And here is an example of how you use it.

    const data = [
      { id: 1,                         mediumPriority: 'bbb', lowestPriority: 'ggg' },
      { id: 2, highestPriority: 'bbb', mediumPriority: 'ccc', lowestPriority: 'ggg' },
      { id: 3,                         mediumPriority: 'aaa', lowestPriority: 'ggg' },
    ];
    
    const priorities = [
      'highestPriority',
      'mediumPriority',
      'lowestPriority'
    ];
    
    
    const sorted = sortByPriority(data, priorities);
    

    This will first sort by the precedence of the attributes, then by the value of the attributes.

    0 讨论(0)
  • 2020-11-21 12:04

    Here's an extensible way to sort by multiple fields.

    homes.sort(function(left, right) {
        var city_order = left.city.localeCompare(right.city);
        var price_order = parseInt(left.price) - parseInt(right.price);
        return city_order || -price_order;
    });
    

    Notes

    • a.localeCompare(b) is universally supported and returns -1,0,1 if a<b,a==b,a>b respectively.
    • Subtraction works on numeric fields.
    • || in the last line gives city priority over price.
    • Negate to reverse order in any field, as in -price_order
    • Date comparison, var date_order = new Date(left.date) - new Date(right.date); works like numerics because date math turns into milliseconds since 1970.
    • Add fields into the or-chain, return city_order || -price_order || date_order;
    0 讨论(0)
  • 2020-11-21 12:04

    Sorting on two date fields and a numeric field example:

    var generic_date =  new Date(2070, 1, 1);
    checkDate = function(date) {
      return Date.parse(date) ? new Date(date): generic_date;
    }
    
    function sortData() {  
      data.sort(function(a,b){
        var deltaEnd = checkDate(b.end) - checkDate(a.end);
        if(deltaEnd) return deltaEnd;
    
        var deltaRank = a.rank - b.rank;
        if (deltaRank) return deltaRank;
    
        var deltaStart = checkDate(b.start) - checkDate(a.start);
        if(deltaStart) return deltaStart;
    
        return 0;
      });
    }
    

    http://jsfiddle.net/hcWgf/57/

    0 讨论(0)
  • 2020-11-21 12:04

    Simplest Way to sort array of object by multiple fields:

     let homes = [ {"h_id":"3",
       "city":"Dallas",
       "state":"TX",
       "zip":"75201",
       "price":"162500"},
      {"h_id":"4",
       "city":"Bevery Hills",
       "state":"CA",
       "zip":"90210",
       "price":"319250"},
      {"h_id":"6",
       "city":"Dallas",
       "state":"TX",
       "zip":"75000",
       "price":"556699"},
      {"h_id":"5",
       "city":"New York",
       "state":"NY",
       "zip":"00010",
       "price":"962500"}
      ];
    
    homes.sort((a, b) => (a.city > b.city) ? 1 : -1);
    

    Output: "Bevery Hills" "Dallas" "Dallas" "Dallas" "New York"

    0 讨论(0)
  • 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<T> {
      key: keyof T;
      reverse?: boolean;
      map?: itemMap;
    }
    
    export function byObjectValues<T extends object>(keys: ((keyof T) | SortConfig<T>)[]): (a: T, b: T) => 0 | 1 | -1 {
      return function(a: T, b: T) {
        const firstKey: keyof T | SortConfig<T> = keys[0];
        const isSimple = typeof firstKey === 'string';
        const key: keyof T = isSimple ? (firstKey as keyof T) : (firstKey as SortConfig<T>).key;
        const reverse: boolean = isSimple ? false : !!(firstKey as SortConfig<T>).reverse;
        const map: itemMap | null = isSimple ? null : (firstKey as SortConfig<T>).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<T>(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<Person>(['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<Language>([
      {
        key: 'code',
        map(code:string) => languageCodeToName(code),
      },
      {
        key: 'version',
        reverse: true,
      }
    ]));
    
    0 讨论(0)
提交回复
热议问题