skip to Main Content

I have an array of objects with name & number properties, with name holding String values and number holding Integers. How can I sort the array using .sort() and a compare function, so that objects with a name property with a certain value appear on top, and then the objects with that name are sorted by the values of their number properties in descending order, and lastly, the object which do not have the name value are sorted in descending order by their names, and then by their values? (Sorry for the long sentence).

For example, I have the following array of objects:

let obj = [
  {'name': 'Seller','number': 2},
  {'name': 'alvino','number': 9},
  {'name': 'nick','number': 6},
  {'name': 'lee','number': 2},
  {'name': 'Seller','number': 1},
  {'name': 'Kevin','number': 4},
  {'name': 'Brady','number': 2},
  {'name': 'Seller','number': 3},
  {'name': 'Alvino','number': 3},
]

I would like that array of objects to result like the following:

[
  { name: 'Seller', 'number': 1 },
  { name: 'Seller', 'number': 2 },
  { name: 'Seller', 'number': 3 },
  { name: 'Alvino', 'number': 9 },
  {'name':'Alvino','number': 3},
  { name: 'Brady', 'number': 2 },
  { name: 'Kevin', 'number': 4 },
  { name: 'Lee', 'number': 2 },
  { name: 'Nick', 'number': 6 },
]

So far, I can sort them first by name equaling ‘Seller’, and by number in descending order:

[
  { name: 'Seller', helpful: 1 },
  { name: 'Seller', helpful: 2 },
  { name: 'Seller', helpful: 3 },
  { name: 'Lee', helpful: 2 },
  { name: 'Brady', helpful: 2 },
  { name: 'Alvino', helpful: 3 },
  { name: 'Kevin', helpful: 4 },
  { name: 'Nick', helpful: 6 },
  { name: 'Alvino', helpful: 9 }
]

, but I am not sure how sort by if name equals ‘Seller’, then by name in descending order, then by number in descending order. Actually, I am not sure if it would be possible to do all three in one comparison function with the sort method, but would like to hear some thoughts on this.

The code I have so far to return by name equaling ‘Seller’ and then by number in descending order is below (with a commented code that I tried out, but did not work as intended):

let sorted = obj.sort((a, b) => {
  if (a.name === 'Seller' && b.name === 'Seller') return a.helpful - b.helpful;
  if (a.name === 'Seller') return -1;
  if (a.name === 'Seller') return 1;
    // if (a.name !== 'Seller' && b.name !== 'Seller') return a.name - b.name;
  
  return a.helpful - b.helpful;
});

3

Answers


  1. An straightforward approach could be to equate the Seller values to empty strings before comparing:

    const obj = [
      {name: 'Seller', number: 2},
      {name: 'Alvino', number: 9},
      {name: 'Nick', number: 6},
      {name: 'Lee', number: 2},
      {name: 'Seller', number: 1},
      {name: 'Kevin', number: 4},
      {name: 'Brady', number: 2},
      {name: 'Seller', number: 3},
      {name: 'Alvino', number: 3},
    ];
    
    obj.sort((a, b) => {
      const aName = a.name === 'Seller' ? '' : a.name;
      const bName = b.name === 'Seller' ? '' : b.name;
      return aName.localeCompare(bName) || a.number - b.number;
    });
    
    console.log(obj);

    This of course assumes that you otherwise have no empty string names to compare to.

    Login or Signup to reply.
  2. Just to reiterate what you’ve said:

    • Primary sort = name matches ‘Seller’
    • Secondary sort = helpful value
    • Tertiary sort = alphabetical name

    Essentially, for each sort, a positive or negative comparison justifies an immediate return and falls through to subsequent comparisons only if the prior comparison is zero (i.e. equal).

    let sorted = obj.sort((a, b) => {
      if (a.name === 'Seller' && b.name !== 'Seller') return -1;
      if (a.name !== 'Seller' && b.name === 'Seller') return 1;
      let helpful=a.helpful - b.helpful;
      if (helpful) return helpful;
      return a.name.localeCompare(b.name);
    });
    
    Login or Signup to reply.
  3. The following snippet works with any value of the name attribute, including the empty string:

    const obj = [
      {name: 'Seller', number: 2},
      {name: 'Alvino', number: 9},
      {name: 'Nick', number: 6},
      {name: '', number: 2},
      {name: 'Seller', number: 1},
      {name: 'Kevin', number: 4},
      {name: 'Brady', number: 2},
      {name: 'Seller', number: 3},
      {name: 'Alvino', number: 3},
    ];
    
    obj.sort((a, b) => {
      return ((a.name=='Seller'?-1:0)+(b.name=='Seller'?1:0) || a.name.localeCompare(b.name)) || a.number - b.number;
    });
    
    console.log(obj);

    The two "or" operators (||) work on two levels: first the a.name and b.name are checked against the value "Seller". If only one of them has that value then the expression before the first || will evaluate to a non-zero value and the expression after the || will not be evaluated anymore. The same goes for the expression after the second || operator. This last expression (the numerical comparison of the helpful attributes) will only take place if all other comparison before it resulted in 0.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search