Home > Net >  Sort grouped array in asc/desc order
Sort grouped array in asc/desc order

Time:10-29

Can anyone assist in sorting the below array in ascending / descending order? The array is to be sorted based on the highest number in each grouping (grouped using brand). Numbers in each group are to be sorted as well:

original_array = [
  { brand: "Ford",   number: "1", },
  { brand: "BMW",    number: "1", },
  { brand: "BMW",    number: "5", },
  { brand: "BMW",    number: "20",},
  { brand: "Toyota", number: "10",}
];

desc_order = [
  { brand: "BMW",    number: "20",},
  { brand: "BMW",    number: "5", },
  { brand: "BMW",    number: "1", },
  { brand: "Toyota", number: "10",},
  { brand: "Ford",   number: "1", }
];

asc_order = [
  { brand: "Ford",   number: "1", },
  { brand: "Toyota", number: "10",},
  { brand: "BMW",    number: "1", },
  { brand: "BMW",    number: "5", },
  { brand: "BMW",    number: "20",}
];

CodePudding user response:

Since the order of the brands in the output depends on maximum values in their group, I would suggest to first create an object that lists the maximum number per brand.

Then use that to sort by, using the following sequence of ordering:

  • First by the maximum value for the brand
  • When that is equal, by the name of the brand (since several brands could have the same maximum number)
  • When that is equal, by the number itself

Implementation:

const array = [ { brand: "Ford", number: "1", }, { brand: "BMW", number: "1", }, { brand: "BMW", number: "5", }, { brand: "BMW", number: "20", }, { brand: "Toyota", number: "10", } ];

// First collect the maximum values per brand as an aggregate:
const aggr = {};
for (let {brand, number} of array) { 
    aggr[brand] = Math.max(number, aggr[brand] ?? number);
}

// Ascending
array.sort((a, b) => aggr[a.brand] - aggr[b.brand] 
                  || a.brand.localeCompare(b.brand)
                  || a.number - b.number);
console.log(array);

// Descending
array.sort((a, b) => aggr[b.brand] - aggr[a.brand]
                  || b.brand.localeCompare(a.brand)
                  || b.number - a.number);
console.log(array);
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

  • Related