8

I'm trying to so sort an array by 2 fields. I have a boolean: isFavorite and a string: name. All the booleans who are true have to be the first items. But I want the array to be alphabetic. This is my code so far (tried multiple things):

data.sort(function (x,y) {
    if (x.isFavorite){
        return -1;
    }
    if (x.isFavorite && !y.isFavorite && (x.name < y.name)){
        return -1;
    }  else if ((x.isFavorite === y.isFavorite) && (x.name === y.name)){
        return 0;
    } else if (x.isFavorite && y.isFavorite && (x.name < y.name)){
        return -1;
    } else if (!x.isFavorite && !y.isFavorite && (x.name > y.name)){
        return 1;
    }
}
Salman A
  • 262,204
  • 82
  • 430
  • 521
Pieter
  • 181
  • 1
  • 7
  • Possible duplicate of [Javascript sort array by two fields](https://stackoverflow.com/questions/6129952/javascript-sort-array-by-two-fields) – Muhammet Enginar Dec 21 '17 at 08:44

5 Answers5

14

Why so much conditions and overlapping ?

Just use logical OR operator in order to sort array by two fields.

Also, I used + (Boolean) in order to force converting to Number.

grouperArray.sort((a, b) => (+a.isFavorite) - (+b.isFavorite) || a.name.localeCompare(b.name));

let data = [{ isFavorite:false, name:'A' }, { isFavorite:true, name:'C' }, { isFavorite:true, name:'B' }];
data.sort((a,b) => (+b.isFavorite) - (+a.isFavorite) || a.name.localeCompare(b.name));
console.log(data);
Mihai Alexandru-Ionut
  • 47,092
  • 13
  • 101
  • 128
3

const data = [
  {isFavorite: false, name: 'b'},
  {isFavorite: false, name: 'f'},
  {isFavorite: true, name: 'c'},
  {isFavorite: true, name: 'a'},
  {isFavorite: false, name: 'd'},
  {isFavorite: true, name: 'g'}
];

const sortedData = data.sort((a, b) => {
  if (a.isFavorite !== b.isFavorite) {
    return a.isFavorite ? -1 : 1;
  } else {
    return a.name > b.name ? 1 : -1;
  }
});
  
console.log(sortedData);
klugjo
  • 19,422
  • 8
  • 57
  • 75
3

Try this one:

const data = [
  {isFavorite: false, name: 'B'}, 
  {isFavorite: false, name: 'A'}, 
  {isFavorite: true, name: 'C'}, 
  {isFavorite: true, name: 'D'},
  {isFavorite: true, name: 'A'},
  {isFavorite: false, name: 'A'},
  {isFavorite: false, name: 'D'},
  {isFavorite: true, name: 'Z'},
];

const compareLoc = (a, b) => a.name.localeCompare(b.name)
const result = [...data.filter(d => d.isFavorite).sort(compareLoc),
...data.filter(d => !d.isFavorite).sort(compareLoc)];
console.log(result);

Following snippet works.

const data = [
  {isFavorite: false, name: 'B'}, 
  {isFavorite: false, name: 'A'}, 
  {isFavorite: true, name: 'C'}, 
  {isFavorite: true, name: 'D'},
  {isFavorite: true, name: 'A'},
  {isFavorite: false, name: 'A'},
  {isFavorite: false, name: 'D'},
  {isFavorite: true, name: 'Z'},
];

data.sort(function (x, y) {
    // if both are true or false, we should compare name attributes
    if (x.isFavorite === y.isFavorite) {
        return x.name.localeCompare(y.name);
    } return x.isFavorite ? -1 : 1
}
)
console.log(data)
Muhammet Enginar
  • 508
  • 6
  • 14
  • This almost works for me, the strange thing is that everything works fine except at the bottom of my dropdown (array), I have a few items that didn't get sorted like this: a-z, a, c, f, g , w => so the first part is perfectly fine, but after Z comes like 10 items that starts again from "a" – Pieter Dec 21 '17 at 09:08
  • That's not weird, he doesn't sort the end of the array. You're supposed to sort every case of a condition, and he only does it in the if statement. Copy/paste the code of the if in the else, and below it, and it should work –  Dec 21 '17 at 09:10
  • Can you post the snippet for clarification? I did what I think you meant but doesn't work – Pieter Dec 21 '17 at 09:39
  • I didn't get the exact point, don't you need isFavorite(a-z) then !isFavorite(a-z)? Why a-z comes after a-z is I order isFavorite = true ones before false ones in all scenarios – Muhammet Enginar Dec 21 '17 at 09:40
  • Exactly, en your snippet does that only at the tail of my array there are a few 'exceptions' : isFavorite(a-z) (works), !isFavorite(a-z) works partly, at the tail I have some items that aren't sorted – Pieter Dec 21 '17 at 09:45
  • can you share a sample please – Muhammet Enginar Dec 21 '17 at 09:49
  • data = [{"a", true}, { "b", true}, {"a", false}, {"g", false}, {"k", false}, {"z", false}, {"b", false}, {"g", false}, {"z", false}] – Pieter Dec 21 '17 at 09:57
  • It' s like it split in 2 different arrays (this was a shortversion because the real one is much longer – Pieter Dec 21 '17 at 09:58
  • 1
    can you check the upper snippet I just shared – Muhammet Enginar Dec 21 '17 at 10:11
0

You problem is that first two if's are overlapping and second if is not reachable if x.isFavorite is true then first if will return.

Also, you are not checking some scenarios like y.isFavorite is true and x.isFavorite is not.

You can write it as

if ( x.isFavorite != y.isFavorite )
{
   return x.isFavorite ? -1 : 1;
}
else
{
   return x.name.localeCompare( y.name );
}
gurvinder372
  • 66,980
  • 10
  • 72
  • 94
0

Here you go :)

var arr = [
  {
    isFavorite: false,
    name: 'a'
  },
  {
    isFavorite: true,
    name: 'b'
  },
  {
    isFavorite: true,
    name: 'c'
  },
  {
    isFavorite: false,
    name: 'c'
  }
];

arr.sort(function (x,y) {
    if (x.isFavorite > y.isFavorite){
        return -1;
    }else if(x.isFavorite == y.isFavorite){
        return x.name > y.name;
    }else{
        return 1;
    }
});

console.log(arr);
Zenoo
  • 12,670
  • 4
  • 45
  • 69