3

I have an array of objects similar in design as listed below. I would like to sort this array first by by the ClassName (alphabetically), then by the StartDate, but I want to preserve the initial sorting. I understand I can likely use sort() to accomplish this but I'm not sure how to preserve the initial sorting w/o breaking the original array into smaller groupings.

var objArray = [
    {
        ClassName: "Excel",
        Location: "Kansas City",
        StartDate: "2/1/2016",
        EndDate: "6/2/2016,"
    },
    {
        ClassName: "Outlook",
        Location: "Kansas City",
        StartDate: "1/1/2016",
        EndDate: "5/2/2016,"
    },
    {
        ClassName: "Excel",
        Location: "Kansas City",
        StartDate: "3/1/2016",
        EndDate: "7/2/2016,"
    }
];

Ideally based on the data above I'd end up with something like this:

var objArray = [
    {
        ClassName: "Excel",
        Location: "Kansas City",
        StartDate: "2/1/2016",
        EndDate: "6/2/2016,"
    },
    {
        ClassName: "Excel",
        Location: "Kansas City",
        StartDate: "3/1/2016",
        EndDate: "7/2/2016,"
    },
    {
        ClassName: "Outlook",
        Location: "Kansas City",
        StartDate: "1/1/2016",
        EndDate: "5/2/2016,"
    }
];

and again for clarity, if there were multiple classes the final sorting would end up looking something like this.

Excel (1/1/2016)
Excel (1/2/2016)
Excel (2/3/2016)
Outlook (1/3/2016)
Outlook (2/3/2016)
Word (1/1/2016)
Word (5/5/2016)
Erik Philips
  • 53,428
  • 11
  • 128
  • 150
Tekk_Know
  • 161
  • 2
  • 12
  • 2
    When you say "preserve the original sorting", you mean a [stable sort](https://en.wikipedia.org/wiki/Sorting_algorithm#Stability)? – salezica Oct 12 '16 at 14:06
  • @Emed Thanks for the link, this helped me find a working solution. I knew somewhere else there had to be a solution already I just couldn't find the right search terms. – Tekk_Know Oct 12 '16 at 14:40

3 Answers3

2

The link @emed pointed to for possible duplicate, had an interesting solution.

My only issue with it would have been performance, as he's doing map's and reduce constantly inside the compare function.

So I've done a slightly modified version, and I've also kept the ability to do reverse sorting.

var objArray = [
    {
        ClassName: "Excel",
        Location: "Kansas City",
        StartDate: "2/1/2016",
        EndDate: "6/2/2016,"
    },
    {
        ClassName: "Outlook",
        Location: "Kansas City",
        StartDate: "1/1/2016",
        EndDate: "5/2/2016,"
    },
    {
        ClassName: "Excel",
        Location: "Kansas City",
        StartDate: "3/1/2016",
        EndDate: "7/2/2016,"
    }
];

objArray.sort(fieldSorter(['ClassName', 'StartDate']));
console.log(objArray);

function fieldSorter(fields) {
    var maps = [];
    fields.map(function (o) {
       var dir = +1;
       if (o[0] === '-') {
          dir = -1;
          o=o.substring(1);
       }
       maps.push({fn:o, dir:dir});
    });
    return function (a, b) {
       var ret = 0;
       maps.some(function (o) {
         if (a[o.fn] > b[o.fn]) ret = o.dir;
         else if (a[o.fn] < b[o.fn]) ret = -o.dir;
         else ret = 0;
         return ret !== 0;
       });
       return ret;
    };
}
Keith
  • 22,005
  • 2
  • 27
  • 44
0

array.sort() is working fine, where you face the issue.

console.log(JSON.stringify(objArray.sort()));

or looking for something like this

objArray.sort(function(a, b) {
    var classA = a.ClassName.toLowerCase(), classB = b.ClassName.toLowerCase();
    if(classA<classB){
        return -1;}
    if(classA>classB){
        return 1;}
    return 0;
});

objArray.sort(function(a, b) {

    var classA = a.ClassName.toLowerCase(), classB = b.ClassName.toLowerCase();
    if(classA===classB){
            var startA =new Date(a.StartDate), startB=new Date(b.StartDate);
            return startA-startB;
     }
    return 0;
});
jeff ayan
  • 819
  • 1
  • 13
  • 16
0

For future reference: this is the function I ended up using to solve the issue. Thank you all for your input:

function fieldSorter(fields) {
    return function (a, b) {
        return fields
            .map(function (o) {
                var dir = 1;
                if (o[0] === '-') {
                   dir = -1;
                   o=o.substring(1);
                }
                if (a[o] > b[o]) return dir;
                if (a[o] < b[o]) return -(dir);
                return 0;
            })
            .reduce(function firstNonZeroValue (p,n) {
                return p ? p : n;
            }, 0);
    };
}
Tekk_Know
  • 161
  • 2
  • 12