Search code examples
javascriptsortingalphanumeric

Sort list of mixed alpha-numeric strings with dots?


I've got an array of objects that I need to sort using the tab property.

All the values are alphanumeric strings.

I've setup an example to show you what I have so far, which I can't seem to get working.

I need my list sorted like doc1, doc2, doc3... doc12, doc13, doc14

// Sort set of values both lexicographically and numerically
function myComparator({ tab: value1 }, { tab: value2 }) {
  const _value1 = parseFloat(value1);
  const _value2 = parseFloat(value2);

  if (_value1 - _value2 === 0) {
    return (value1 > value2) ? 1 : -1;
  } else {
    return _value1 - _value2;
  }
}

const myArray = [
  { doc: 'Doc1', tab: '7' },
  { doc: 'Doc2', tab: '7A' },
  { doc: 'Doc3', tab: '7B' },
  { doc: 'Doc4', tab: '7.0001' },
  { doc: 'Doc5', tab: '7.01' },
  { doc: 'Doc6', tab: '7.01A' },
  { doc: 'Doc7', tab: '7.1' },
  { doc: 'Doc8', tab: '7.1A' },
  { doc: 'Doc9', tab: '7.2' },
  { doc: 'Doc10', tab: '7.3' },
  { doc: 'Doc11', tab: '7.10' },
  { doc: 'Doc12', tab: '7.11' },
  { doc: 'Doc13', tab: '7.20' },
  { doc: 'Doc14', tab: '7.34' },
];

myArray.sort(myComparator);

let html = '';

for (let i = 0; i < myArray.length; i++) {
  html += '<li>' + myArray[i].doc + '</li>';
}

document.getElementById('results').innerHTML = html;
<ul id="results" />


Solution

  • Pulled together numerous other code snippets to find a solution. See below:

    function customSort(data, key, order) {
        function isNumber(v) {
            return (+v).toString() === v;
        }
    
        function isRoman(s) {
            // http://stackoverflow.com/a/267405/1447675
            return /^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$/i.test(s);
        }
    
        function parseRoman(s) {
            var val = { M: 1000, D: 500, C: 100, L: 50, X: 10, V: 5, I: 1 };
            return s.toUpperCase().split('').reduce(function (r, a, i, aa) {
                return val[a] < val[aa[i + 1]] ? r - val[a] : r + val[a];
            }, 0);
        }
    
        var sort = {
                asc: function (a, b) {
                    var i = 0,
                        l = Math.min(a.value.length, b.value.length);
    
                    while (i < l && a.value[i] === b.value[i]) {
                        i++;
                    }
                    if (i === l) {
                        return a.value.length - b.value.length;
                    }
                    if (isNumber(a.value[i]) && isNumber(b.value[i])) {
                        return a.value[i] - b.value[i];
                    }
                    if (isRoman(a.value[i]) && isRoman(b.value[i])) {
                        return parseRoman(a.value[i]) - parseRoman(b.value[i]);
                    }
                    return a.value[i].localeCompare(b.value[i]);
                },
                desc: function (a, b) {
                    return sort.asc(b, a);
                }
            };
            
            var mapped = data.map(function (el, i) {
                var string = el[key].replace(/\d(?=[a-z])|[a-z](?=\.)/gi, '$&. .'),
                    regex = /(\d+)|([^0-9.]+)/g,
                    m,
                    parts = [];
    
                while ((m = regex.exec(string)) !== null) {
                    parts.push(m[0]);
                }
                return { index: i, value: parts, o: el, string: string };
            });
    
        mapped.sort(sort[order] || sort.asc);
        return mapped.map(function (el) {
            return data[el.index];
        });
    }
    
    var arr = [
    	{ doc: 'Doc10', tab: '7.3' },
    	{ doc: 'Doc2', tab: '7B' },
      { doc: 'Doc13', tab: '7.20' },
      { doc: 'Doc0', tab: '7' },
      { doc: 'Doc1', tab: '7A' },
      { doc: 'Doc3', tab: '7C' },
      { doc: 'Doc4', tab: '7.0001' },
      { doc: 'Doc5', tab: '7.01' },
      { doc: 'Doc6', tab: '7.01A' },
      { doc: 'Doc7', tab: '7.1' },
      { doc: 'Doc8', tab: '7.1A' },
      { doc: 'Doc9', tab: '7.2' },
      { doc: 'Doc11', tab: '7.10' },
      { doc: 'Doc12', tab: '7.11' },
      { doc: 'Doc14', tab: '7.34' }
    ];
    
    const myArray = customSort(arr, 'tab');
    
    let html = '';
    
    for (let i = 0; i < myArray.length; i++) {
      html += '<li>' + myArray[i].doc + '</li>';
    }
    
    document.getElementById('results').innerHTML = html;
    <ul id="results" />

    The correct order I was looking for was:

    • 7
    • 7A
    • 7B
    • 7.0001
    • 7.01
    • 7.01A
    • 7.1
    • 7.1A
    • 7.2
    • 7.3
    • 7.10
    • 7.11
    • 7.20
    • 7.34