2

In javascript, I have an array of items like so:

[
  'title',
  'firstname',
  'company',
  '[m]usr_phone'
  '[m]usr_city'
]

I would like to sort this using a custom array sort function so that all the non [m] items are sorted at the top, and all the [m] items are sorted and pushed to the bottom (after all the non [m] items)

To achieve this I tried a sort function like this:

function(a, b) {
            if (!a.indexOf('[m]') && b.indexOf('[m]') === 0
                || a.indexOf('[m]') && b.indexOf('[m]')) {
                    return -1;
            }

            if (a.indexOf('[m]') === 0 && !b.indexOf('[m]')) {
                return 1;
            }

            return 0;
        }

But couldn't get it to work properly. I would like the output to be:

[
  'company',
  'firstname',
  'title',
  '[m]usr_city'
  '[m]usr_phone'
]

Thanks for your help!

simon_www
  • 489
  • 2
  • 5
  • 13

2 Answers2

2

You could check the prefix and sort later by String#localeCompare.

var array = ['title', 'firstname', 'company', '[m]usr_phone', '[m]usr_city'];

array.sort(function (a, b) {
    return (a.slice(0, 3) === '[m]') - (b.slice(0, 3) === '[m]') || a.localeCompare(b);
});

console.log(array);
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • I think [you shouldn't use `localeCompare` if you don't need a *locale* comparison](https://stackoverflow.com/q/14677060/1048572). – Bergi Oct 26 '17 at 18:23
  • Accepting this as the answer, works great. Interesting note about localeCompare. I'm not to fussed as the list is small (no more than 20 items), however if the list grew considerably then performance may be an issue. You can see that here: https://jsperf.com/operator-vs-localecompage/3 – simon_www Oct 27 '17 at 09:17
0

You want to compare items in the same “class” (i.e. either starting with [m] or not) the same way, so use a.startsWith("[m]") == b.startsWith("[m]") to do this, and then use String#localeCompare.

console.log([
  "company",
  "firstname",
  "title",
  "[m]usr_phone",
  "[m]usr_city"
].sort((a, b) => {
  if (a.startsWith("[m]") == b.startsWith("[m]")) {
    return a.localeCompare(b);
  } else {
    return (a.startsWith("[m]") ?
      1 :
      -1);
  }
}));
Sebastian Simon
  • 18,263
  • 7
  • 55
  • 75