How to sort strings in JavaScript

Viewed 554983

I have a list of objects I wish to sort based on a field attr of type string. I tried using -

list.sort(function (a, b) {
    return a.attr - b.attr
})

but found that - doesn't appear to work with strings in JavaScript. How can I sort a list of objects based on an attribute with type string?

16 Answers

Use String.prototype.localeCompare a per your example:

list.sort(function (a, b) {
    return ('' + a.attr).localeCompare(b.attr);
})

We force a.attr to be a string to avoid exceptions. localeCompare has been supported since Internet Explorer 6 and Firefox 1. You may also see the following code used that doesn't respect a locale:

if (item1.attr < item2.attr)
  return -1;
if ( item1.attr > item2.attr)
  return 1;
return 0;

since strings can be compared directly in javascript, this will do the job

list.sort(function (a, b) {
    return a.attr > b.attr ? 1: -1;
})

the subtraction in a sort function is used only when non alphabetical (numerical) sort is desired and of course it does not work with strings

You should use > or < and == here. So the solution would be:

list.sort(function(item1, item2) {
    var val1 = item1.attr,
        val2 = item2.attr;
    if (val1 == val2) return 0;
    if (val1 > val2) return 1;
    if (val1 < val2) return -1;
});

Nested ternary arrow function

(a,b) => (a < b ? -1 : a > b ? 1 : 0)

In javascript, we use the .localCompare method to sort strings

For Typescript

const data = ["jane", "mike", "salome", "ababus", "buisa", "dennis"];

const sort = (arr: string[], mode?: 'desc' | 'asc') => 
  !mode || mode === "asc"
    ? arr.sort((a, b) => a.localeCompare(b))
    : arr.sort((a, b) => b.localeCompare(a));


console.log(sort(data, 'desc'));// [ 'salome', 'mike', 'jane', 'dennis', 'buisa', 'ababus' ]
console.log(sort(data, 'asc')); // [ 'ababus', 'buisa', 'dennis', 'jane', 'mike', 'salome' ]


For JS

const data = ["jane", "mike", "salome", "ababus", "buisa", "dennis"];

/**
 * @param {string[]} arr
 * @param {"asc"|"desc"} mode
 */
const sort = (arr, mode = "asc") =>
  !mode || mode === "asc"
    ? arr.sort((a, b) => a.localeCompare(b))
    : arr.sort((a, b) => b.localeCompare(a));

console.log(sort(data, 'desc'));// [ 'salome', 'mike', 'jane', 'dennis', 'buisa', 'ababus' ]
console.log(sort(data, 'asc')); // [ 'ababus', 'buisa', 'dennis', 'jane', 'mike', 'salome' ]

An explanation of why the approach in the question doesn't work:

let products = [
    { name: "laptop", price: 800 },
    { name: "phone", price:200},
    { name: "tv", price: 1200}
];
products.sort( (a, b) => {
    {let value= a.name - b.name; console.log(value); return value}
});

> 2 NaN

Subtraction between strings returns NaN.

Echoing @Alejadro's answer, the right approach is--

products.sort( (a,b) => a.name > b.name ? 1 : -1 )

There should be ascending and descending orders functions

if (order === 'asc') {
  return a.localeCompare(b);
}
return b.localeCompare(a);

If you want to control locales (or case or accent), then use Intl.collator:

const collator = new Intl.Collator();
list.sort((a, b) => collator.compare(a.attr, b.attr));

You can construct collator like:

new Intl.Collator("en");
new Intl.Collator("en", {sensitivity: "case"});
...

see the above link for doc.

Note: unlike some other solutions, it handles null, undefined the JS way, i.e. moves them to the end.

Use sort() straight forward without any - or <

const areas = ['hill', 'beach', 'desert', 'mountain']
console.log(areas.sort())

// To print in descending way
console.log(areas.sort().reverse())

<!doctype html>
<html>
<body>
<p id = "myString">zyxtspqnmdba</p>
<p id = "orderedString"></p>
<script>
var myString = document.getElementById("myString").innerHTML;
orderString(myString);
function orderString(str) {
    var i = 0;
    var myArray = str.split("");
    while (i < str.length){
        var j = i + 1;
        while (j < str.length) {
            if (myArray[j] < myArray[i]){
                var temp = myArray[i];
                myArray[i] = myArray[j];
                myArray[j] = temp;
            }
            j++;
        }
        i++;
    }
    var newString = myArray.join("");
    document.getElementById("orderedString").innerHTML = newString;
}
</script>
</body>
</html>
var str = ['v','a','da','c','k','l']
var b = str.join('').split('').sort().reverse().join('')
console.log(b)
Related