0

I have seen questions and answers how to sort array by one value (text or number) and by two numbers (years and count of something).

How can I sort by one string in Ascending order and another string in special order?

Here is one object from array

var stop = {
    type: "S", // values can be S, C or H. Should ordered S, C and then H.
    street: "SW Dummy St." // Should be sorted in ascending order
}

And expected end result should look like this

var data = [
    { type: 'S', year: 'SW Karp' },
    { type: 'S', year: 'SW Walker' },
    { type: 'C', year: 'SW Greth' },
    { type: 'C', year: 'SW Main' }
    { type: 'H', year: 'SW Dummy' }
];
jM2.me
  • 3,839
  • 12
  • 44
  • 58
  • 1
    possible duplicate of [How to sort an array of objects by multiple fields?](http://stackoverflow.com/questions/6913512/how-to-sort-an-array-of-objects-by-multiple-fields) – Felix Kling Mar 08 '12 at 13:28
  • Just to make sure: You can use the function in my answer there and use a special primer for the `type`, returning e.g. a number for each letter, such as `0` for `S`, `1` for `C` and `2` for `H`: `data.sort(sort_by({name: 'type', primer: function(x) { return ({'S':0, 'C':1, 'H':2})[x];}}, 'street'));` – Felix Kling Mar 08 '12 at 13:40

3 Answers3

5

The Array.sort() method accepts a sort function, which allows you to implement the sorting yourself.

data.sort(function (a, b) {
    // Specify the priorities of the types here. Because they're all one character
    // in length, we can do simply as a string. If you start having more advanced
    // types (multiple chars etc), you'll need to change this to an array.
    var order = 'SCH';
    var typeA = order.indexOf(a.type);
    var typeB = order.indexOf(b.type);

    // We only need to look at the year if the type is the same
    if (typeA == typeB) {
        if (a.year < b.year) {
            return -1;
        } else if (a.year == b.year) {
            return 0;
        } else {
            return 1;
        }

    // Otherwise we inspect by type
    } else {
        return typeA - typeB;
    }
});

Array.sort() expects 0 to be returned if a == b, < 0 if a < b and > 0 if a > b.

You can see this working here; http://jsfiddle.net/32zPu/

Matt
  • 74,352
  • 26
  • 153
  • 180
2

I've upvoted Matt's answer, but wanted to add a slightly different approach for getting the sort order from the type which can work for values beyond just single characters and a bit shorter way to compare the year values:

data.sort(function(a, b) {
    var order = {"S": 1,"C": 2,"H": 3}, typeA, typeB;
    if (a.type != b.type) {
        typeA = order[a.type] || -1;
        typeB = order[b.type] || -1;
        return(typeA - typeB);
    } else {
        return(a.year.localeCompare(b.year));
    }
});

Working demo: http://jsfiddle.net/jfriend00/X3rSj/

jfriend00
  • 683,504
  • 96
  • 985
  • 979
0

You can pass a custom function to the array sort method that lets you define how the items are sorted. Something like this should work (your unsorted data would be in the 'data' var):

function sortFunc (item1, item2) {
  var sortOrder = 'SCH';
  if (item1.type != item2.type)
  {
    return sortOrder.indexOf(item1.type) - sortOrder.indexOf(item2.type);
  }
  else
  {
    return item1.year.localeCompare(item2.year);
  }
}

var sortedData = data.sort(sortFunc);
Canute Bigler
  • 220
  • 1
  • 9