Ravi Tuvar
Ravi Tuvar

Reputation: 191

Sorting in Javascript with special characters

I have an array with the following values

asd sdf dsdf 1sadf *sdf !sdf @asdf _asd .sadf (sadf )sadf #sadf 
^asdf &asdf %asdf -sadf =sadf +sadf -sdf

and i want to sort it in javascript in the following way in to three parts.

  1. word starting from special character
  2. word starting from digit
  3. word starting from alphabets.

So this should be the sequence of the sorted array.

EDIT: Here's a function that I've been experimenting with:

function naturalSort(a, b) {
   a = a.path.toLowerCase();
   b = b.path.toLowerCase();
   var re = /(^-?[0-9]+(\.?[0-9]*)[df]?e?[0-9]?$|^0x[0-9a-f]+$|[0-9]+)/gi,
  sre = /(^[ ]*|[ ]*|[_]*$)/g,
  dre = /(^([\w ]+,?[\w ]+)?[\w ]+,?[\w ]+\d+:\d+(:\d+)?[\w ]?|^\d{1,4}[\/\-]\d{1,4}[\/\-]\d{1,4}|^\w+, \w+ \d+, \d{4})/,
  hre = /^0x[0-9a-f]+$/i,
  ore = /^0/,
   // convert all to strings and trim()
  x = a.toString().replace(sre, '') || '',
  y = b.toString().replace(sre, '') || '',
   // chunk/tokenize
  xN = x.replace(re, '\0$1\0').replace(/\0$/, '').replace(/^\0/, '').split('\0'),
  yN = y.replace(re, '\0$1\0').replace(/\0$/, '').replace(/^\0/, '').split('\0'),
   // numeric, hex or date detection
  xD = parseInt(x.match(hre)) || (xN.length != 1 && x.match(dre) && Date.parse(x)),
  yD = parseInt(y.match(hre)) || xD && y.match(dre) && Date.parse(y) || null;
   // first try and sort Hex codes or Dates
   if (yD)
    if (xD < yD) return -1;
    else if (xD > yD) return 1;
   // natural sorting through split numeric strings and default strings
   for (var cLoc = 0, numS = Math.max(xN.length, yN.length); cLoc < numS; cLoc++) {
    // find floats not starting with '0', string or 0 if not defined (Clint Priest)
    oFxNcL = !(xN[cLoc] || '').match(ore) && parseFloat(xN[cLoc]) || xN[cLoc] || 0;
    oFyNcL = !(yN[cLoc] || '').match(ore) && parseFloat(yN[cLoc]) || yN[cLoc] || 0;
    // handle numeric vs string comparison - number < string - (Kyle Adams)
    if (isNaN(oFxNcL) !== isNaN(oFyNcL)) return (isNaN(oFxNcL)) ? -1 : 1;
    // rely on string comparison if different types - i.e. '02' < 2 != '02' < '2'
    else if (typeof oFxNcL !== typeof oFyNcL) {
     oFxNcL += '';
     oFyNcL += '';
    }
    if (oFxNcL <= oFyNcL) return -1;
    if (oFxNcL >= oFyNcL) return 1;
   }
   return 0;
  }

Upvotes: 4

Views: 20285

Answers (3)

user3785328
user3785328

Reputation: 898

Two easy solutions:

using Intl.Collator

myArray.sort(Intl.Collator().compare)

using localeCompare

myArray.sort((a, b) => a.localeCompare(b))

Intl.Collator is more perfomant

Upvotes: 11

technophyle
technophyle

Reputation: 9169

This could also work:

function sortArray(a, b) {
  const digitRegex = /^\d/;
  const alphabetRegex = /^[a-zA-Z]/;
  const symbolRegex = /^[^\w\s]/;
  
  const scoreA =  symbolRegex.test(a) * 1 || digitRegex.test(a) * 10 || alphabetRegex.test(a) * 100;
  const scoreB =  symbolRegex.test(b) * 1 || digitRegex.test(b) * 10 || alphabetRegex.test(b) * 100;
  
  if (scoreA !== scoreB) {
    return scoreA - scoreB;
  }
  
  if (a < b) {
    return -1;
  } else if (a > b) {
    return 1;
  }
  
  return 0;
}

const a = ['def', '%rec', '456', '^we', '123', 'abc'].sort(sortArray);

console.log(a);

Upvotes: 1

Ja͢ck
Ja͢ck

Reputation: 173662

To be honest, I have no idea what your posted function does ... at all.

The following approach compares strings on their first character, using positional occurrence. Strings with the same first character are sorted regularly.

Btw, didn't test for empty strings.

function MySort(alphabet)
{
    return function(a, b) {
        var index_a = alphabet.indexOf(a[0]),
        index_b = alphabet.indexOf(b[0]);

        if (index_a === index_b) {
            // same first character, sort regular
            if (a < b) {
                return -1;
            } else if (a > b) {
                return 1;
            }
            return 0;
        } else {
            return index_a - index_b;
        }
    }
}

var items = ['asd','sdf', 'dsdf', '1sadf', '*sdf', '!sdf', '@asdf', '_asd', '.sadf', '(sadf', ')sadf', '#sadf', '^asdf', '&asdf', '%asdf', '-sadf', '=sadf', '+sadf', '-sdf', 'sef'],
sorter = MySort('*!@_.()#^&%-=+01234567989abcdefghijklmnopqrstuvwxyz');

console.log(items.sort(sorter));

Output:

["*sdf", "!sdf", "@asdf", "_asd", ".sadf", "(sadf", ")sadf", "#sadf", "^asdf", 
 "&asdf", "%asdf", "-sadf", "-sdf", "=sadf", "+sadf", "1sadf", 
 "asd", "dsdf", "sdf", "sef"]

Upvotes: 22

Related Questions