How to sort an array of objects by multiple fields?

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

    Here's my solution based on the Schwartzian transform idiom, hope you find it useful.

    function sortByAttribute(array, ...attrs) {
      // generate an array of predicate-objects contains
      // property getter, and descending indicator
      let predicates = attrs.map(pred => {
        let descending = pred.charAt(0) === '-' ? -1 : 1;
        pred = pred.replace(/^-/, '');
        return {
          getter: o => o[pred],
          descend: descending
        };
      });
      // schwartzian transform idiom implementation. aka: "decorate-sort-undecorate"
      return array.map(item => {
        return {
          src: item,
          compareValues: predicates.map(predicate => predicate.getter(item))
        };
      })
      .sort((o1, o2) => {
        let i = -1, result = 0;
        while (++i < predicates.length) {
          if (o1.compareValues[i] < o2.compareValues[i]) result = -1;
          if (o1.compareValues[i] > o2.compareValues[i]) result = 1;
          if (result *= predicates[i].descend) break;
        }
        return result;
      })
      .map(item => item.src);
    }
    

    Here's an example how to use it:

    let games = [
      { name: 'Pako',              rating: 4.21 },
      { name: 'Hill Climb Racing', rating: 3.88 },
      { name: 'Angry Birds Space', rating: 3.88 },
      { name: 'Badland',           rating: 4.33 }
    ];
    
    // sort by one attribute
    console.log(sortByAttribute(games, 'name'));
    // sort by mupltiple attributes
    console.log(sortByAttribute(games, '-rating', 'name'));
    

提交回复
热议问题