I believe the best way to do this is just do everything with a custom sort
. The sort callback function is given two arguments, the first array element and the second array element which it is comparing. Then you can use any logic you wish within the body of the callback to decide what to return. If -1 is returned, then this means the first element should be before the second element. If 1 is returned, then this means the second element should be before the first element. If 0 is returned, this means both elements are equal and thus should remain side-by-side with each other so no other elements get inserted into the middle during sorting.
To sort alphabetically, you can compare two strings with each other using the <
, >
, <=
, >=
operators. Then the result would be a boolean true or false, so you'd want to return either -1
or 1
depending whether you wanted ascending or descending - in respect to the way you compared them. You can also check for equality and return 0
if you think you'll be encountering duplicate items in your array and wanted to have a slightly faster implementation which will be barely noticeable unless you were working on large data.
To add exceptions to the alphabetical sorting, I'd suggest creating a numeric representation for the first element, then create another numeric representation for the second element. Use negative numbers to indicate sorting among exceptions, where the smaller the number would indicate the closer to the beginning of the array it should go. Then use a 0 for everything else to indicate it isn't an exception. Then finally check for the existence of exceptions using a simple if statement. In the case of no exceptions, sort alphabetical. Otherwise we have an exception and should sort in the order of whichever is represented by the smaller number.
var inputArray = [{
name: "Mobile Uploads"
}, {
name: "Profile Pictures"
}, {
name: "Reports"
}, {
name: "Instagram Photos"
}, {
name: "Facebook"
}, {
name: "My Account"
}, {
name: "Twitter"
}];
var sortedArray = inputArray.slice(0);//copy of the original array as sort is destructive.
sortedArray.sort(function(a,b){
var aIndex = 0, bIndex = 0;
switch(a.name)
{
case "Profile Pictures":
aIndex = -3;
break;
case "Mobile Uploads":
aIndex = -2;
break;
case "Instagram Photos":
aIndex = -1;
break;
}
switch(b.name)
{
case "Profile Pictures":
bIndex = -3;
break;
case "Mobile Uploads":
bIndex = -2;
break;
case "Instagram Photos":
bIndex = -1;
break;
}
if(aIndex < 0 || bIndex < 0)//Check if either element being compared needs special treatment
{
//in the case of two exceptions, we want the smallest one to be sorted first
//otherwise in the case of one exception the other element would be a 0
return aIndex < bIndex ? -1 : 1;//ascending
}
else
{
//otherwise just sort in alpabetical order comparing strings with the less than operator
return a.name < b.name ? -1 : 1;//ascending
}
});
//Before
console.log('Before:');
console.log(inputArray.map(function(v){
return v.name;
}).join(', '));//Mobile Uploads, Profile Pictures, Reports, Instagram Photos, Facebook, My Account, Twitter
//After
console.log('After:');
console.log(sortedArray.map(function(v){
return v.name;
}).join(', '));//Profile Pictures, Mobile Uploads, Instagram Photos, Facebook, My Account, Reports, Twitter