136

W3CSchools has this example:

var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.sort();
fruits.reverse();

Is this the most efficient way to sort strings in descending order in Javascript?

Update

One of the answers is using localeCompare. Just curious whether if we do reverse(), will that work for all locales (Maybe this is a separate question - Just let me know in the comments)?

9
  • 1
    By what measure of efficiency? Commented Aug 26, 2018 at 20:42
  • Possible duplicate stackoverflow.com/questions/1063007/… Commented Aug 26, 2018 at 20:49
  • 1
    .sort() and .reverse() is already the most efficient way. Commented Aug 26, 2018 at 20:52
  • 1
    .sort((a, b) => -(a>b)||+(a<b)) Commented Aug 26, 2018 at 20:53
  • 2
    reverse() doesn't care about the locales, it only modifies the indexes of the array in reverse order Commented Aug 26, 2018 at 21:25

5 Answers 5

239

If you consider

obj.sort().reverse();

VS

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

VS

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

The performance winner is : obj.sort().reverse().

Testing with an array of 10.000 elements, obj.sort().reverse() is faster than obj.sort( function ) (except on chrome), and obj.sort( function ) (using localCompare).

Performance test here :

var results = [[],[],[]]

for(let i = 0; i < 100; i++){
  const randomArrayGen = () => Array.from({length: 10000}, () => Math.random().toString(30));
  const randomArray = randomArrayGen();
  const copyArray = x => x.slice();

  obj = copyArray(randomArray);
  let t0 = performance.now();
  obj.sort().reverse();
  let t1 = performance.now();

  obj = copyArray(randomArray);
  let t2 = performance.now();
  obj.sort((a, b) => (a > b ? -1 : 1))
  let t3 = performance.now();

  obj = copyArray(randomArray);
  let t4 = performance.now();
  obj.sort((a, b) => b.localeCompare(a))
  let t5 = performance.now();  

  results[0].push(t1 - t0);
  results[1].push(t3 - t2);
  results[2].push(t5 - t4);  
}

const calculateAverage = x => x.reduce((a,b) => a + b) / x.length ;

console.log("obj.sort().reverse():                   " + calculateAverage(results[0]));
console.log("obj.sort((a, b) => (a > b ? -1 : 1)):   " + calculateAverage(results[1]));
console.log("obj.sort((a, b) => b.localeCompare(a)): " + calculateAverage(results[2]));

Sign up to request clarification or add additional context in comments.

9 Comments

i uodated my answer and the jsperf, to include the localCompare case
the same situation woud be (a,b)=>b.localeCompare(a)) not b.localeCompare(a, 'es', {sensitivity: 'base'})) that is for special characters. obj.sort().reverse() doesn't work with special characters
Node benchmarks on my machine show #2 as being the fastest: obj.sort().reverse(): 3.090556930010207 obj.sort((a, b) => (a > b ? -1 : 1)): 2.7984550699871034 obj.sort((a, b) => b.localeCompare(a)): 10.975987620060332
obj.sort((a, b) => b - a) only works for numbers, not strings!
|
9

Using just sort and reverse a > Z , that is wrong if you want to order lower cases and upper cases strings:

var arr = ["a","b","c","A","B","Z"];

arr.sort().reverse();

console.log(arr)//<-- [ 'c', 'b', 'a', 'Z', 'B', 'A' ] wrong!!!

English characters

var arr = ["a","b","c","A","B","Z"];

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

console.log(arr)

Special characters using locales, in this example es (spanish)

var arr = ["a", "á", "b","c","A","Á","B","Z"];

arr.sort((a, b) => b.localeCompare(a, 'es', {sensitivity: 'base'}))


console.log(arr)

sensitivity in this case is base:

Only strings that differ in base letters compare as unequal. Examples: a ≠ b, a = á, a = A.

3 Comments

What makes you think it is wrong? OP asked to make the sorting descending, not to make it case-invariant.
@Bergi Using sort and reverse could solve the problem that OP is facing using that specific set of data, it is not good as a general solution in my opinion. Also OP said in the title strings, not certain kind of strings. Either way "is wrong" is a bad generalization.
@Bergi "is wrong" is a bit strong, but it's very useful to point out behaviour that OP might want like case insensitivity and to specify that the default string sort is case-sensitive! Don't assume questions writers know 100% what they want and what related things they might need to take into account.
4

The easiest way to revers the order of sorting is by swapping the operands. In ES2015 that's as easy as [b, a] = [a, b]. A full example:

function compareWithOrder(a, b, shouldReverse = false) {
  if (shouldReverse) {
    [b, a] = [a, b]
  }
  return yourComparatorFn(a, b)
}

Comments

0

var arr = ["a","b","c","A","B","Z"];

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

console.log(arr)

1 Comment

This doesn't address the question. What are your metrics for efficiency?
0

I know this is an old question, but an interesting one. This is my solution for a non-special character's input.

var arr = ["a","b","c","A","B","Z"];

  console.log(arr.sort((a,b)=> {
      const lastCodeIn = b.toLowerCase().charCodeAt();
      const lastCode = b.charCodeAt();
      const firstCodeIn = a.toLowerCase().charCodeAt();
      const firstCode = a.charCodeAt();

      if(lastCodeIn - firstCodeIn === 0){
        return lastCode - firstCode;
      }
      return lastCodeIn - firstCodeIn;
    })
  );//[ 'Z', 'c', 'b', 'B', 'a', 'A' ]

The reason is that ascii code for UPPER case are lower than lower case.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.