0

From what it said, it sounds very simple, but I wasn't succeeded to achieve the perfect result in Chrome (I did it in IE)

So I have an object:

var objs=[
{ name: "water", type: "cold" },
{ name: "tea", type: "hot" },
{ name: "coffee", type: "hot" },
{ name: "choco", type: "cold" }
];

I sorted it by name, ascending and I got the expected result:

  1. choco,cold
  2. coffee, hot
  3. tea, hot
  4. water, cold

I got the same result both in IE and Chrome,

Then, I sort it again by type, ascending, and my expectation:

  1. choco, cold
  2. water, cold
  3. coffee, hot
  4. tea, hot

But I only got the expected result in IE, while in Chrome the result was almost the same except that "water" came at the top (it ruins the first sorting)

any general approach idea? (I need to keep it one function call per field, not sorting by multiple fields in one function at the same time)

My sort method was like this:

function SortBy(key,Asc,method){
  var GetKey=function(x) {return method ? method(x[key]) : x[key] };
  return function(a,b){
    var A=GetKey(a), B=GetKey(b);
    return ((A<B) ? -1 : ((A>B) ? 1 : 0)) * [-1,1][+!!Asc];
  }
}

var sortedObjects=Clone(objs); //clone the current objs

sortedObjects.sort(SortBy("name" , true, function(x){
  if (typeof(x)=="string") return x.toLowerCase(); else return x;
}));

objs=sortedObjects; //got the first result

sortedObjects.sort(SortBy("type",true,function(x){
  if (typeof(x)=="string") return x.toLowerCase(); else return x;
}));

objs=sortedObjects;

EDITED here is the fiddle (the problem is the "Water"): DEMO

5
  • Can you create a fiddle? Commented Jul 29, 2014 at 14:23
  • This works for me in google chrome. Can you post a JSFiddle or something? Commented Jul 29, 2014 at 14:23
  • Why do you need to keep it one function call per field? This inefficient Commented Jul 29, 2014 at 14:28
  • I'll create a fiddle, apparently it works (I used sample data), if I use more data then it will not work Commented Jul 29, 2014 at 14:34
  • The result you're expecting isn't the result you can assume according to the spec, please see the last edit to my answer Commented Jul 29, 2014 at 15:40

2 Answers 2

1

If we read the ES5 spec §15.4.4.11 Array.prototype.sort, the very second sentence states

The sort is not necessarily stable (that is, elements that compare equal do not necessarily remain in their original order)

That is to say, in JavaScript, if the comparator says two things are equal (by giving 0), it doesn't matter if they get swapped or not and hence in some environments they may swapped due to some other reason such as their hashes or just the implementation.

i.e. The result you experience is a valid result of sort as defined by the spec and repeating the same sort may even give different results each time


Hopefully I won't get downvoted too heavily for this, but if you do it as one function then you don't need to iterate through the array as many times and you'll avoid your unexpected result

/*  list = multiSort(list [, obj, ...])
 *  where e.g. obj = {
 *      key: "keyToLookAt",
 *      optional comparator: function (a, b) {return a<b || ((a===b)-1);},
 *      optional ascending: default true
 *  }
*/

var multiSort = (function () {
    function generateSorter(key, comparator, ascending) {
        ascending = 2 * !!ascending - 1;
        if (comparator) {
            return function sorter(a, b) {
                return ascending * comparator(a[key], b[key]);
            };
        }
        return function sorter(a, b) {
            a = a[key];
            b = b[key];
            return ascending * (a < b ? -1 : a > b ? 1 : 0);
        };
    }
    function sortManager(sorters) {
        return function (a, b) {
            var ret, i = 0;
            for (; i < sorters.length; ++i) {
                ret = sorters[i](a, b);
                if (ret !== 0) return ret;
            }
            return 0;
        };
    }
    function multiSort(list) {
        var i = 1, sorters = [];
        for (; i < arguments.length; ++i) {
            sorters.push(generateSorter(
                arguments[i].key,
                arguments[i].comparator,
                'ascending' in arguments[i] ? arguments[i].ascending : 1
            ));
        }
        list.sort(sortManager(sorters));
        return list;
    }
    return multiSort;
}());

And then when using it, the "most strict" sort rule goes first

multiSort(
    [
        { name: "water", type: "cold" },
        { name: "tea", type: "hot" },
        { name: "coffee", type: "hot" },
        { name: "choco", type: "cold" }
    ],
    {key: 'type'},
    {key: 'name'}
);
/*
[
    { "name": "choco" , "type": "cold" },
    { "name": "water" , "type": "cold" },
    { "name": "coffee", "type": "hot" },
    { "name": "tea"   , "type": "hot" }
]
*/
Sign up to request clarification or add additional context in comments.

Comments

0

I created a CodePen to test and work fine... I write the same idea in more readable code

function SortBy(key, isAsc, fn){
     fn = fn || function (x){ return x; };

    return function(objA, objB){
       var a = fn(objA[key]);
       var b = fn(objB[key]);

       var isGreater = isAsc ? 1 : -1;
       var isLesser = -isGreater;
       var isSame = 0;

       if( a > b ) return isGreater;
       if( a == b ) return isSame;
       if( a < b ) return isLesser;
       return -1; //to down the undefined

     }  

}

http://codepen.io/anon/pen/sGgDq edited and tested with a lot of data

p.s.: I used codepen because jsfiddle not open in my work

3 Comments

Apparently with my sample data with only 4 data it works fine, I got more data in the fiddle, which goes wrong when sorted in Chrome
send the fiddle :D, to me works fine with a lot of data, if I found the trouble I fix
the output is different if you open it in chrome and IE (I expect the result just like in IE)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.