Sort Array Elements (String with Numbers), Natural Sort

Javascript : natural sort of alphanumerical strings

This is now possible in modern browsers using localeCompare. By passing the numeric: true option, it will smartly recognize numbers. You can do case-insensitive using sensitivity: 'base'. Tested in Chrome, Firefox, and IE11.

Here's an example. It returns 1, meaning 10 goes after 2:

'10'.localeCompare('2', undefined, {numeric: true, sensitivity: 'base'})

For performance when sorting large numbers of strings, the article says:

When comparing large numbers of strings, such as in sorting large arrays, it is better to create an Intl.Collator object and use the function provided by its compare property. Docs link

var collator = new Intl.Collator(undefined, {numeric: true, sensitivity: 'base'});
var myArray = ['1_Document', '11_Document', '2_Document'];
console.log(myArray.sort(collator.compare));

Sort Array of numeric & alphabetical elements (Natural Sort)

From http://snipplr.com/view/36012/javascript-natural-sort/ by mrhoo:

Array.prototype.naturalSort= function(){
var a, b, a1, b1, rx=/(\d+)|(\D+)/g, rd=/\d+/;
return this.sort(function(as, bs){
a= String(as).toLowerCase().match(rx);
b= String(bs).toLowerCase().match(rx);
while(a.length && b.length){
a1= a.shift();
b1= b.shift();
if(rd.test(a1) || rd.test(b1)){
if(!rd.test(a1)) return 1;
if(!rd.test(b1)) return -1;
if(a1!= b1) return a1-b1;
}
else if(a1!= b1) return a1> b1? 1: -1;
}
return a.length- b.length;
});
}

Or, from Alphanum: Javascript Natural Sorting Algorithm by Brian Huisman:

Array.prototype.alphanumSort = function(caseInsensitive) {
for (var z = 0, t; t = this[z]; z++) {
this[z] = [];
var x = 0, y = -1, n = 0, i, j;

while (i = (j = t.charAt(x++)).charCodeAt(0)) {
var m = (i == 46 || (i >=48 && i <= 57));
if (m !== n) {
this[z][++y] = "";
n = m;
}
this[z][y] += j;
}
}

this.sort(function(a, b) {
for (var x = 0, aa, bb; (aa = a[x]) && (bb = b[x]); x++) {
if (caseInsensitive) {
aa = aa.toLowerCase();
bb = bb.toLowerCase();
}
if (aa !== bb) {
var c = Number(aa), d = Number(bb);
if (c == aa && d == bb) {
return c - d;
} else return (aa > bb) ? 1 : -1;
}
}
return a.length - b.length;
});

for (var z = 0; z < this.length; z++)
this[z] = this[z].join("");
}

Sort Array Elements (string with numbers), natural sort

This is called "natural sort" and can be implemented in JS like this:

function naturalCompare(a, b) {

var ax = [], bx = [];

a.replace(/(\d+)|(\D+)/g, function(_, $1, $2) { ax.push([$1 || Infinity, $2 || ""]) });

b.replace(/(\d+)|(\D+)/g, function(_, $1, $2) { bx.push([$1 || Infinity, $2 || ""]) });



while(ax.length && bx.length) {

var an = ax.shift();

var bn = bx.shift();

var nn = (an[0] - bn[0]) || an[1].localeCompare(bn[1]);

if(nn) return nn;

}

return ax.length - bx.length;

}

/////////////////////////

test = [

"img12.png",

"img10.png",

"img2.png",

"img1.png",

"img101.png",

"img101a.png",

"abc10.jpg",

"abc10",

"abc2.jpg",

"20.jpg",

"20",

"abc",

"abc2",

""

];

test.sort(naturalCompare)

document.write("<pre>" + JSON.stringify(test,0,3));

How to natural-sort a collection of objects in JavaScript?

Ascending and Descending order

const arr = [{name: "John", size: "100"},{name: "John", size: "80"},{name: "John", size: "82"},{name: "John", size: "110"},{name: "John", size: "70"},{name: "John", size: "M"},{name: "John", size: "S"},{name: "John", size: "XS"},{name: "John", size: "L"},{name: "John", size: "XL"}],

handler = (a, b, desc) => {

if (isNaN(+a) && isNaN(+b)) return (desc ? b.localeCompare(a) : a.localeCompare(b));

else if (!isNaN(+a) && !isNaN(+b)) return (desc ? (+b - +a) : (+a - +b));

else if (isNaN(+a)) return (desc ? -1 : 1);

else return (desc ? 1 : -1);

},

descending = arr.sort(({size: a}, {size: b}) => handler(a, b, true)),

ascending = [...arr].sort(({size: a}, {size: b}) => handler(a, b));

console.log("Ascending")

console.log(ascending);

console.log("Descending")

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

How to sort an array of numeric strings which also contain numbers. (natural ordering) in PHP

Use natsort

This function implements a sort algorithm that orders alphanumeric strings in the way a human being would while maintaining key/value associations. This is described as a "natural ordering".

Sort number part of a string?

You could use String#localeCompare with options.

var array = ['abc.def1.1', 'abc.def1.1234', 'abc.def1.1235', 'abc.def1.2', 'abc.def1.234'];

array.sort(function (a,b) {

return a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' });

});

console.log(array);

Javascript natural sort objects

You could use sorting with map and String#localeCompare with options

sensitivity

Which differences in the strings should lead to non-zero result values. Possible values are:

  • "base": Only strings that differ in base letters compare as unequal. Examples: a ≠ b, a = á, a = A.
  • "accent": Only strings that differ in base letters or accents and other diacritic marks compare as unequal. Examples: a ≠ b, a ≠ á, a = A.
  • "case": Only strings that differ in base letters or case compare as unequal. Examples: a ≠ b, a = á, a ≠ A.
  • "variant": Strings that differ in base letters, accents and other diacritic marks, or case compare as unequal. Other differences may also be taken into consideration. Examples: a ≠ b, a ≠ á, a ≠ A.

The default is "variant" for usage "sort"; it's locale dependent for usage "search".

numeric

Whether numeric collation should be used, such that "1" < "2" < "10". Possible values are true and false; the default is false. This option can be set through an options property or through a Unicode extension key; if both are provided, the options property takes precedence. Implementations are not required to support this property.

var array = ['Ex 10', 'Ex 2', 'a 10.1', 'a 1.1', 'a 10.0', 'a 2.0'];

array.sort((a, b) => a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' }));

console.log(array)

javascript natural sort

The solution is to use localeCompare(), the options of which are here.

Now we can sort this array

const items = ['3rd', 'Apple', '24th', '99 in the shade', 'Dec3', 'Dec', 'Dec20', '10000', 'house', 'house11b', 'house11a', 'house99', '101', '$1.23'];

with one line of code

items.sort( ( a, b ) => a.localeCompare( b, navigator.languages[ 0 ] || navigator.language, { numeric: true, ignorePunctuation: true } ) );

yielding

['$1.23', '3rd', '24th', '99 in the shade', '101', '10000', 'Apple', 'Dec', 'Dec3', 'Dec20', 'house', 'house11a', 'house11b', 'house99']

Credit for this elegant solution belongs here.

EDIT

I'm not satisfied. This works, but only for strings. I'd like to have a sort that will chew on numbers and arrays too. I really want a one-size-fits-all, if I can get it. With that in mind, this update

items.sort( ( a, b ) => ( a + '' ).localeCompare( b, navigator.languages[ 0 ] || navigator.language, { numeric: true, ignorePunctuation: true } ) );

using this updated array (containing strings, integers, decimals and a nested array ['a',1,2])

let items = ['3rd', 'Apple', .99, '24th', 'apple.sauce', '99 in the shade', 99, 'Dec3', 'B', 'a', 'Dec', 'Dec20', 12, '10000', 'house', 1.24, '1.22', 'house11b', 1, 'house11a', 'house99', '101', 400.23, '$1.23', ['a',1,2]];

gets us closer with

['$1.23', 0.99, 1, '1.22', 1.24, '3rd', 12, '24th', 99, '99 in the shade', '101', 400.23, '10000', 'a', Array(3), 'Apple', 'apple.sauce', 'B', 'Dec', 'Dec3', 'Dec20', 'house', 'house11a', 'house11b', 'house99']

LASTLY

Now, to satisfy my own OCD tendencies, I want the currency value $1.23 to line up with the rest of the decimal values. Since indulging OCD often comes at a cost, I'm using this ugly ternary:

( a + '' ).substr( 0, 1 ) === '$' ? ( a + '' ).substr( 1, ( a + '' ).length ) : ( a + '' )

Also, I'll specify the language instead of grabbing it from the browser and set base sensitivity (which is language dependent).

So a case insensitive sort ignorePunctuation: true that treats strings as numbers (as much as possible) numeric: true, and respects the order of graphemes in the language sensitivity: 'base' as well as sorts USD currency as decimals, is this

items.sort( ( a, b ) => ( ( a + '' ).substr( 0, 1 ) === '$' ? ( a + '' ).substr( 1, ( a + '' ).length ) : ( a + '' ) ).localeCompare( b, 'en', { ignorePunctuation: true, numeric: true, sensitivity: 'base' } ) );

which gives us this

[0.99, 1, '1.22', '$1.23', 1.24, '3rd', 12, '24th', 99, '99 in the shade', '101', 400.23, '10000', 'a', Array(3), 'Apple', 'apple.sauce', 'B', 'Dec', 'Dec3', 'Dec20', 'house', 'house11a', 'house11b', 'house99']

which is as close to a perfect one-size-fits-all as I need it to be. /p>


Related Topics



Leave a reply



Submit