- mutates the original array - to prevent it, make a copy (
const sorted = origArr.slice().sort()
orconst sorted1 = [...origArr]
) of the array and then sort the copy - makes a specific order of elements
- returns array
- sorts by a string value (even if it's an array of numbers)
There's plenty of ways to sort arrays in JavaScript (and using .sort()
is probably one of the slowest ones, but it is important to understand it and how it works).
- Simple
.sort()
- sorts the values as strings in alphabetical and ascending order.
Yes, that is correct - although they are numbers, they will be sorted as strings. This means (and we will see it very soon) that although 11
is greater than 2
, 11
will be sorted before 2
because "2" is bigger than "1". Because of this, the .sort()
method will lead to incorrect result when sorting numbers.
Let's work on the following array:
const unsorted = [1, 4, 2, 11, 42];
Now apply the .sort()
on the unsorted
array of numbers:
unsorted.sort();
// [ 1, 11, 2, 4, 42 ] // <== sorted by string value!!!
Since we didn't make a safe copy of the array, let's check what happened with the original array:
console.log(`original: ${unsorted}`); // original: 1,11,2,4,42
Ups, it's sorted and we lost our original array. 😢
Let's see how we would approach with a best-practices in place:
const sorted1 = unsorted.slice().sort();
// const sorted1 = [...unsorted].sort();
console.log(`sorted: ${sorted1}`); // sorted: 1,11,2,4,42
console.log(`original: ${unsorted}`); // original: 1,4,2,11,42
You can fix this by providing a compare function.
Additional example
const x = "11";
const y = "2";
console.log(x < y); // true
The provided code is using JavaScript and it compares two strings, x and y, using the less than (<
) operator. In this case, both x
and y
contain string representations of numbers, "11" and "2," respectively.
When you use the less than operator to compare strings in JavaScript, it performs a lexicographic (dictionary-style) comparison, character by character, from left to right. In this comparison, it starts by comparing the first characters of the strings. In this case, it compares "1" from x
and "2" from y
.
Since "1" comes before "2" in the lexicographic order (it has a lower character code in the character encoding used by JavaScript, typically UTF-16), the expression x < y evaluates to true.
So, the statement console.log(x < y) will output true to the console because "11" is indeed less than "2" when comparing them as strings, character by character. It's important to note that this behavior is specific to string comparisons, and if you were comparing numbers, you'd get a different result.
- Using compare function with
.sort()
- yeah, that's it ✅
If we want to sort numbers in numerical order, we must include in the sort method one parameter: a compare function.
Let's get a new unsorted array:
const randomNumbers = [3, 1, 9, 8, 42, 1221];
The compareFunction
parameter takes two arguments, which are typically referred to as a and b. The function should return a negative value if a should be sorted before b, a positive value if a should be sorted after b, or zero if a and b are equal.
function compareFunction(a,b){
// < 0 --> a comes first
// = 0 --> a nothing changes
// > 0 --> b comes first
return a - b;
}
🆙 Sorting numbers ascending
const ascRandom = randomNumbers.slice().sort((a, b) => a - b);
console.log(`sorted asc: ${ascRandom}`); // sorted asc: 1,3,8,9,42,1221
console.log(`original: ${randomNumbers}`); // original: 3,1,9,8,42,1221
We can see that numbers are sorted in ascending order and original array stayed untouched.
⏬ Sorting numbers descending
We will use the same array, randomNumbers
:
const descRandom = randomNumbers.slice().sort((a, b) => b - a);
console.log(`sorted desc: ${descRandom}`); // orted desc: 1221,42,9,8,3,1
console.log(`original: ${randomNumbers}`); // original: 3,1,9,8,42,1221
The compare function should return a negative, zero or positive value, depending on the arguments.
Example:
When comparing 3 and 10, the .sort()
method calls the compare function(3,10).
The function calculates 3-10 and returns -7 (a negative value).
The sort function will sort 3 as a value lower than 10.
Let's see how it works when we sort the strings. We will be demoing on the array of words
:
const words = ["Hello", "great", "First", "A", "a", "how"];
⬆️ Sorting strings ascending
Now, let's make a copy of the array and apply the simple sort
. This method applied without compare function will sort strings in ascending order.
Note: The capitalized letters will come before lowercased ones.
const wordsAsc = words.slice().sort();
console.log(`words asc: ${wordsAsc}`); // words asc: A,First,Hello,a,great,how
console.log(`original words: ${words}`); // original words: Hello,great,First,A,a,how
To surpass this limitation, we should apply .toLowercase()
on all words and then compare them:
const properWordsSortAsc = words.slice().sort((a,b) => {
a = a.toLowerCase();
b = b.toLowerCase();
if( a === b) {
return 0;
} else if(a > b) {
return 1;
} else {
return -1;
}
});
console.log(properWordsSortAsc);
// [ 'A', 'a', 'First', 'great', 'Hello', 'how' ]
🔽 Sorting strings descending
When in need to sort strings in descending order, we need to pass the following compare function (still working with the words
array):
const wordsDesc = words.slice().sort((a, b) => {
if( a === b){
return 0;
} else if(a > b) {
return -1;
} else {
return 1;
}
});
console.log(`words desc: ${wordsDesc}`); // words desc: how,great,a,Hello,First,A
console.log(`original words: ${words}`); // original words: Hello,great,First,A,a,how
const sortedByLength = words.slice().sort((a, b) => {
if(a.length > b.length) {
return 1;
}
if(a.length < b.length) {
return -1;
}
if(a.length === b.length) {
return 0;
}
})
console.log('---> ', sortedByLength);
// ---> ['A', 'a', 'how', 'Hello', 'Hello', 'great', 'First' ]
const arr = [
{ title: 'Carrot', votes: 3 },
{ title: 'Milk', votes: 2 },
{ title: 'Banana', votes: 2 },
{ title: 'Apple', votes: 1 }
];
const byVotesAlphabetically = arr.slice().sort((a, b) => {
if (a.votes > b.votes) return -1;
if (a.votes < b.votes) return 1;
if (a.title > b.title) return 1;
if (a.title < b.title) return -1;
});
console.log(byVotesAlphabetically);
// [
// { title: 'Carrot', votes: 3 },
// { title: 'Banana', votes: 2 },
// { title: 'Milk', votes: 2 },
// { title: 'Apple', votes: 1 }
// ]