Home > Software design >  Sorting an Array by number order when it contains letters
Sorting an Array by number order when it contains letters

Time:03-16

I have an array which contains groups information. I am sorting them by their group name as follows:

groups.sort().sort(function (a, b) {
  if (a.name < b.name) {
    return -1;
  }
  if (a.name > b.name) {
    return 1;
  }
  return 0;
});

This returns them in this name order:

10, 11, 13, 7, 8, 9, A10, A11, A7, A8, A9

However i am trying to order them like this:

7, A7, 8, A8, 9, A9, 10, A10, 11, A11, 13

Can anyone help me with this?

CodePudding user response:

You could get the digits and sort by this number, or zero if no value is found

const
    getNumber = s => s.toString().match(/\d /)?.[0] || 0,
    array = ['A1', 1, 10, 11, 13, 7, 8, 9, 'A10', 'A11', 'A7', 'A8', 'A9', '1'];

array.sort((a, b) => getNumber(a) - getNumber(b) || a.toString().localeCompare(b));

console.log(...array);

Approach by using an object and a function for a property accessor.

const
    getNumber = s => s.toString().match(/\d /)?.[0] || 0,
    customSort = (a, b) => getNumber(a) - getNumber(b) || a.toString().localeCompare(b),
    getValue = ({ value }) => value,
    sortBy = (sortFn, valueFn) => (a, b) => sortFn(valueFn(a), valueFn(b)),
    array = [{ value: 'A1' }, { value: 1 }, { value: 10 }, { value: 11 }, { value: 13 }, { value: 7 }, { value: 8 }, { value: 9 }, { value: 'A10' }, { value: 'A11' }, { value: 'A7' }, { value: 'A8' }, { value: 'A9' }, { value: '1A' }];

array.sort(sortBy(customSort, getValue));

console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }

CodePudding user response:

First sort the items as strings, next sort again using conversion of the array items to Number within the sort lambda. Something like:

const x = `Z9,10,11,B11,13,7,8,B8,9,A10,A11,A7,A8,A9`.split(`,`)
  .map(v => ({name: v}));
// first sort on string values  
const sortedx = x.sort( (a, b) => a.name.localeCompare(b.name))
// second sort on numeric values
  .sort( (a, b) =>  a.name.replace(/\D/g, ``) -  b.name.replace(/\D/g, ``));
console.log(`${sortedx.map(v => v.name )}`);

CodePudding user response:

You can use this:

groups.sort().sort(function (a, b) {
  var aa = parseInt(a.name.replace(/[^\d.-]/g, ''));
  var bb = parseInt(b.name.replace(/[^\d.-]/g, ''));
  if (aa < bb)
    return -1;  
  if (aa > bb)
    return 1;
  
  // When == 0, order using full name, not only the number
  if (a.name < b.name)
    return -1;  
  return a.name > b.name ? 1 : 0;
});

The regular expression takes only the number part, parse to int and use it for the comparison. For the same number ("7" and "A7", for example), we use the original name, to sort with it.

  • Related