Reputation: 191
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.
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
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
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
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