I am trying to sort an array of objects through one property. The array is getting sorted properly when I sort it using a compare function. But the order of the array is changing after the sort. What can I do to prevent it?.
I already thought of a solution, where I can separate the data:0 elements into an array and sort the remaining elements and concatenate both. Just wondering whether there is a simple way of doing it?
Note: hex property is a object which I can't use in the compare function. hex can have any value or string.
var arr = [
{hex: "100x213123", data: 0},
{hex: "20x213223", data: 0},
{hex: "30x313123", data: 200},
{hex: "40x413123", data: 0},
{hex: "50x213123", data: 0},
{hex: "60x213123", data: 0},
{hex: "70x213123", data: 100},
{hex: "80x213123", data: 0},
{hex: "90x213123", data: 100},
{hex: "100x213123",data: 100},
{hex: "110x213123", data: 0},
{hex: "120x213123", data: 0}
].sort(function (item1,item2){
return item1.data - item2.data;
});
console.log(JSON.stringify(arr));
Result
[{"hex":"100x213123","data":0},
{"hex":"120x213123","data":0},
{"hex":"110x213123","data":0},
{"hex":"40x413123","data":0},
{"hex":"50x213123","data":0},
{"hex":"60x213123","data":0},
{"hex":"20x213223","data":0},
{"hex":"80x213123","data":0},
{"hex":"90x213123","data":100},
{"hex":"100x213123","data":100},
{"hex":"70x213123","data":100},
{"hex":"30x313123","data":200}]
Expected
[{hex: "100x213123", data: 0},
{hex: "20x213223", data: 0},
{hex: "40x413123", data: 0},
{hex: "50x213123", data: 0},
{hex: "60x213123", data: 0},
{hex: "80x213123", data: 0},
{hex: "110x213123", data: 0},
{hex: "120x213123", data: 0},
{hex: "70x213123", data: 100},
{hex: "90x213123", data: 100},
{hex: "100x213123",data: 100},
{hex: "30x313123", data: 200}]
Any Ideas?
3 Answers 3
You need to have a secondary sort if the data is same and sort on the hex values:
var arr = [
{hex: "10x213123", data: 0},
{hex: "20x213223", data: 0},
{hex: "30x313123", data: 200},
{hex: "40x413123", data: 0},
{hex: "50x213123", data: 0},
{hex: "60x213123", data: 0},
{hex: "70x213123", data: 100},
{hex: "80x213123", data: 0},
{hex: "90x213123", data: 100},
{hex: "100x213123",data: 100},
{hex: "110x213123", data: 0},
{hex: "120x213123", data: 0}
].sort(function(item1, item2) {
if (item1.data !== item2.data)
return item1.data - item2.data;
else
return item1.hex.split("x")[0] - item2.hex.split("x")[0]
});
console.log(JSON.stringify(arr));
So the best way is to add an index and then sort it as the second key.
var arr = [
{hex: "10x213123", data: 0},
{hex: "20x213223", data: 0},
{hex: "30x313123", data: 200},
{hex: "40x413123", data: 0},
{hex: "50x213123", data: 0},
{hex: "60x213123", data: 0},
{hex: "70x213123", data: 100},
{hex: "80x213123", data: 0},
{hex: "90x213123", data: 100},
{hex: "100x213123",data: 100},
{hex: "110x213123", data: 0},
{hex: "120x213123", data: 0}
].map(function (v, i) {
v.index = i;
return v;
}).sort(function(item1, item2) {
if (item1.data !== item2.data)
return item1.data - item2.data;
else
return item1.index - item2.index
}).map(function (v) {
delete v.index;
return v;
});
console.log(JSON.stringify(arr));
And remove the index.
Comments
This behavior happens because Javascript's Array.sort is not guaranteed to be stable. This Stack Overflow question explores which browsers implements Javascript's Array.sort as a stable implementation, and points to a quick solution on how to convert an unstable sort to a stable one.
In general, if you want to avoid adding an "old index" field (or are unable to), you will want to have a copy of the array that you are sorting - this lets you sort by the sorter's comparator values first, then to sort by their old index if the comparison function determines that the two elements are equal.
For example, you might consider something like this:
function stable_sort(original_array) {
var shallow_copy_array = original_array.slice();
original_array.sort(function(left_element, right_element) {
var comparison_result = left_element.data - right_element.data;
if (comparison_result === 0) {
return shallow_copy_array.indexOf(left_element) - shallow_copy_array.indexOf(right_element);
} else {
return comparison_result;
}
});
}
Comments
.sort(function (item1,item2){
if (item1.data > item2.data) {
return 1;
} else if (item1.data < item2.data)
{
return -1;
} else if (item1.hex > item2.hex) {
return 1;
} else if (item1.hex < item2.hex) {
return -1;
} else {
return 0;
}
});
But the order of the array is changing after the sort- that's what sorting does - it changes the order of the array