33

What is the best method to sort a sparse array and keep the elements on the same indexes? For example:

a[0] = 3, 
a[1] = 2, 
a[2] = 6,
a[7] = 4,
a[8] = 5,

I would like after the sort to have

a[0] = 2, 
a[1] = 3, 
a[2] = 4, 
a[7] = 5, 
a[8] = 6.
1
  • Maybe you could try to google with the key words : 'sort', 'associative array', 'by value' if I understand well your issue. Commented Aug 27, 2012 at 7:24

4 Answers 4

198

Here's one approach. It copies the defined array elements to a new array and saves their indexes. It sorts the new array and then puts the sorted results back into the indexes that were previously used.

var a = [];
a[0] = 3;
a[1] = 2; 
a[2] = 6; 
a[7] = 4; 
a[8] = 5;


// sortFn is optional array sort callback function, 
// defaults to numeric sort if not passed
function sortSparseArray(arr, sortFn) {
    var tempArr = [], indexes = [];
    for (var i = 0; i < arr.length; i++) {
        // find all array elements that are not undefined
        if (arr[i] !== undefined) {
            tempArr.push(arr[i]);    // save value
            indexes.push(i);         // save index
        }
    }
    // sort values (numeric sort by default)
    if (!sortFn) {
        sortFn = function(a,b) {
            return(a - b);
        }
    }
    tempArr.sort(sortFn);
    // put sorted values back into the indexes in the original array that were used
    for (var i = 0; i < indexes.length; i++) {
        arr[indexes[i]] = tempArr[i];
    }
    return(arr);
}

Working demo: http://jsfiddle.net/jfriend00/3ank4/

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

19 Comments

@jfriend000, what if I directly use .sort() ?
And @jfriend00 had never thought writing a 'stacksort compliant' code would get him so many upvotes and points ;)
@OrhanC1 - I fixed it. The code was doing a lexicographic sort (so it would have worked for string entries). Now, it is set for a numeric sort.
Powerful upvoting due to stacksort :)
Next up: @jfriend00 goes rogue and changes the code to be entirely malicious. Hundreds of xkcd readers are affected.
|
3

You can

  1. Use filter or Object.values to obtain an array with the values of your sparse array.
  2. Then sort that array, from largest to smaller. Be aware it's not stable, which may be specially problematic if some values are not numeric. You can use your own sorting implementation.
  3. Use map and pop to obtain the desired array. Assign it to a.
var b = a.filter(function(x) {
    return true;
}).sort(function(x,y) {
    return y - x;
});
a = a.map([].pop, b);

Or, in ECMAScript 2017,

a = a.map([].pop, Object.values(a).sort((x,y) => y-x));

4 Comments

The variable b is not needed in the ES5 code, but I used it to make the code more readable.
As a bonus, the original a is unmodified if assign the map return to a new variable. Nice work, Oriol. I hate that [].sort mutates by default.
If we can assume that all elements in the sparse array are numeric (and without this assumption the sort callback would behave inconsistently!), then we can filter elements just with a.filter(() => true) or Object.values(a).
@GOTO0 Thanks, probably I forgot filter uses HasProperty to skip non-existing properties.
0
var arr = [1,2,3,4,5,6,7,8,9,10];
// functions sort
function sIncrease(i, ii) { // ascending
 if (i > ii)
 return 1;
 else if (i < ii)
 return -1;
 else
 return 0;
}
function sDecrease(i, ii) { //descending
 if (i > ii)
 return -1;
 else if (i < ii)
 return 1;
 else
 return 0;
}
function sRand() { // random
 return Math.random() > 0.5 ? 1 : -1;
}
arr.sort(sIncrease); // return [1,2,3,4,5,6,7,8,9,10]
arr.sort(sDecrease); // return [10,9,8,7,6,5,4,3,2,1]
arr.sort(sRand); // return random array for examle [1,10,3,4,8,6,9,2,7,5]

1 Comment

I don't think this is what the question was really asking.
0
// Update for your needs ('position' to your key).

function updateIndexes( list ) {

    list.sort( ( a, b ) => a.position - b.position )

    list.forEach( ( _, index, arr ) => {

        arr[ index ].position = index

    } )

}

var myList = [
   { position: 8 },
   { position: 5 },
   { position: 1 },
   { position: 9 }
]

updateIndexes( myList )

// Result:

var myList = [
   { position: 1 },
   { position: 2 },
   { position: 3 },
   { position: 4 }
]

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.