2

I need to sort an array of strings by their length, leaving the strings in their original order if they are of the same length. This is my code:

arr.sort(function(a, b) {
  return b.length - a.length;
});

It works until the number of elements with the same length > 10, but after that the instability in the sort method changes the order. I have tried to find a way to keep the order the same, but I'm not having any luck. Any suggestions?

3
  • 2
    Stability is a property of the sorting algorithm. Javascript sort is not stable, so you have to work around this by first creating a new array arr2 of pairs (el, i) where el is the element of arr at position i, then sort these pairs lexicographically, finally strip down the second i element. Alternatively write your own custom stable sorting algorithm (e.g. merge sort). Commented Jun 26, 2016 at 16:48
  • See stackoverflow.com/questions/1427608/… Commented Jun 26, 2016 at 16:48
  • Just implement some stable sorting algorithm manually. Commented Jun 26, 2016 at 16:57

3 Answers 3

1

You have to sort pairs (element, index) instead of actual elements. This way you'll have stable sort.

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

Comments

1
arr.map(function(str, i){
    return {
        index: i,
        length: str.length,
        value: str
    }
}).sort(function(a, b){
    return b.length - a.length || a.index - b.index;
}).map(function(obj){
    return obj.value;
})

This may seem like to much overhead, but as soon as you have to somehow compute the value you are sorting on, it's faster to compute it once and store it to some Object, than computing it potentially in a n*(n-1) operation.

So this approach in sorting is often the more performant one.

Or you generallize the two mapping-tasks:

var valueIndex = function(value,index){ return {value:value,index:index} };
var getValue = function(obj){ return obj.value };

arr.map(valueIndex)
    .sort(function(a, b){ 
        return b.value.length - a.value.length || a.index - b.index
    })
    .map(getValue);

ES6

var valueIndex = (value,index) => { return {value,index} };
var getValue = ({value}) => value;

arr.map(valueIndex)
    .sort((a, b) => b.value.length - a.value.length || a.index - b.index)
    .map(getValue);

Comments

0

You could use sorting with map, where the map contains the length and the index of original sorting.

// the array to be sorted
var stringArray = ['Tom', 'Mia', 'Michael', 'Bob', 'Thomas', 'Joy'];

// temporary array holds objects with position and sort-value
var mapped = stringArray.map(function (el, i) {
    return { index: i, value: el.length };
});

// sorting the mapped array containing the reduced values
mapped.sort(function (a, b) {
    return b.value - a.value || a.index - b.index;
});

// container for the resulting order
var result = mapped.map(function (el) {
    return stringArray[el.index];
});

console.log(result);

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.