5

I have the following array structure

[{
  name: "Mobile Uploads"
}, {
  name: "Profile Pictures"
}, {
  name: "Reports"
}, {
  name: "Instagram Photos"
}, {
  name: "Facebook"
}, {
  name: "My Account"
}, {
  name: "Twitter"
}]

I want to reorder the array so that its in the following order: Profile Pictures, Mobile Uploads, Instagram Photos, and the objects afterwards are in alpabetical order.

Dave
  • 10,748
  • 3
  • 43
  • 54
Brown PO
  • 457
  • 3
  • 9
  • 13
  • 2
    Rather than thinking of moving elements around, think of creating a new array with the elements in the order you want. You can use routines like `sort`, or `map`, or `filter` to do that. That's how we usually do it in JS. By the way, you've used the word "efficiently" here. I see that quite a bit in JS questions. Technically speaking, that means "fast performance". Is that what you mean, or do you really mean, as is often the case, "in a way that's easy to read and write"? –  Jul 19 '16 at 03:12
  • Hey @Brown, so you are looking for 2 orders: Profile Pictures, Mobile Uploads, Instagram Photos and Instagram Photos, Mobile Uploads, Profile Pictures – Ayan Jul 19 '16 at 03:15
  • 2
    http://stackoverflow.com/questions/2440700/reordering-arrays – Venkat Jul 19 '16 at 04:02

3 Answers3

10

What you want to do is to make an object that holds the sort exceptions. Then you can write a custom sort() function that accounts for your exceptions.

var list = [{
  name: "Date"
}, {
  name: "Mobile Uploads"
}, {
  name: "Profile Pictures"
}, {
  name: "Fig"
}, {
  name: "Instagram Photos"
}, {
  name: "Cherry"
}, {
  name: "Apple"
}, {
  name: "Banana"
}];

var exceptions = {
  "Profile Pictures": 1,
  "Mobile Uploads": 2,
  "Instagram Photos": 3
}

list.sort(function(a, b) {
  if (exceptions[a.name] && exceptions[b.name]) {
    //if both items are exceptions
    return exceptions[a.name] - exceptions[b.name];
  } else if (exceptions[a.name]) {
    //only `a` is in exceptions, sort it to front
    return -1;
  } else if (exceptions[b.name]) {
    //only `b` is in exceptions, sort it to back
    return 1;
  } else {
    //no exceptions to account for, return alphabetic sort
    return a.name.localeCompare(b.name);
  }
});

console.log(list);
Dave
  • 10,748
  • 3
  • 43
  • 54
0
    var algo = [{
        name: "Mobile Uploads"
     },
     { 
        name: "Zeta"
     },
     {
        name: "Beta"
     },
     {
        name: "Alfa"
     },
     { 
        name: "Profile Pictures"
     },
     {
        name: "Instagram Photos"
     }]

var compare = function(a,b){
    var weight = {"Profile Pictures":1, "Mobile Uploads":2, "Instagram Photos":3}
    ,   nameA = a.name
    ,   weightA = weight[nameA] || 100
    ,   nameB = b.name
    ,   weightB = weight[nameB] || 100

    if(weightA != weightB){
        return weightA - weightB;
    }else{
        return nameA > nameB;
    }

}

console.log(algo.sort(compare));

the idea is assign weight to manage the sort.

0

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
Ultimater
  • 4,647
  • 2
  • 29
  • 43
  • [I'd avoid that comparison](http://stackoverflow.com/a/20892652/1048572) – Bergi Jul 19 '16 at 05:10
  • 1
    Returning zero is a waste unless the array will encounter duplicates, and even still, the array will sort just fine without considering such. In the OP's question, it looks like he or she is trying to build a navigation bar of some sort which wouldn't have duplicates in the first place, and thus the faster way is not to consider duplicates. – Ultimater Jul 19 '16 at 05:29