0

I need to sort through an array of strings that contain letters / numbers / and leading zeros. If null it must go to the top of the list and appear as an empty string. I've looked and researched many different ways but nothing that sorts the way I'm expecting it to.

Initial Array:

input = [
    { value: null },
    { value: '' },
    { value: '-' },
    { value: '0' },
    { value: 'A1' },
    { value: '0001' },
    { value: '01' },
    { value: '1' },
    { value: '01.008A' },
    { value: '01.008' },
    { value: '02' },
    { value: 'A' },
    { value: '10' },
    { value: '100A1' },
    { value: '10-1' },
    { value: '100' },
    { value: '001' },
    { value: '2' },
  ]

Expected Output:

  1. " "
  2. " "
  3. "-"
  4. "0"
  5. "0001"
  6. "001"
  7. "01"
  8. "01.008"
  9. "01.008A"
  10. "1"
  11. "02"
  12. "2"
  13. "10"
  14. "10-1"
  15. "100"
  16. "100A1"
  17. "A"
  18. "A1"

EDIT: (My Original Code)

function sortAlphanumeric<T>(this: Array<T>, property: string): Array<T> {
  var collator = new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' });

  function dynamicSort(property) {
    var sortOrder = 1;

    if (property[0] === "-") {
      sortOrder = -1;
      property = property.substr(1);
    }

    return function (a, b) {
      if (sortOrder == -1) {
        return b[property].localeCompare(a[property]);
      } else {
        return a[property].localeCompare(b[property]);
      }
    }
  }
  return this.sort(dynamicSort(property)).sort((a, b) => {
    var nullToEmptyString = '';

    if (a[property] === null) {
      a[property] = nullToEmptyString;
    }

    if (b[property] === null) {
      b[property] = nullToEmptyString;
    }
    return collator.compare(a[property], b[property]);
  });
}

1 Answers1

0

This should do it:

input.sort(({value:a}, {value:b}) => {
  const ai = parseInt(a, 10), bi = parseInt(b, 10);
  return (b == null) - (a == null)
    || (ai - bi)
    || (a > b) - (b > a);
}).map(x => x.value || "")
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Why not map the array before sorting it ? Also, for string comparison there is [.localeCompare(..)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare) – Titus Jan 09 '20 at 16:20
  • @Titus The `map` was more of an afterthought for "*null must appear as an empty string*", I consider it optional. I'm not using `localeCompare` because the comparison under some locale is rather unpredictable, I value the simple standard string comparison. – Bergi Jan 09 '20 at 16:29
  • Amazing solution. This has been breaking my head. – Revolver_FOX Jan 09 '20 at 16:33