Sign up ×
Stack Overflow is a community of 4.7 million programmers, just like you, helping each other. Join them; it only takes a minute:

This question already has an answer here:

So I have this data:

var data = [
      [
       {name:"John", age:32, x:false}, 
       {name:"Mark", age:44, x:false}, 
       {name:"John", age:21, x:true}
      ],

      [
       {name:"John", age:65, x:false}, 
       {name:"Mark", age:77, x:false}, 
       {name:"John", age:78, x:true}
      ],

      [
       {name:"John", age:11, x:false}, 
       {name:"Mark", age:15, x:false}, 
       {name:"John", age:65, x:true}
      ]
    ];

What I want to do is to rearrange this data so the object which contains x = true is at the first position [0]. Here how this should look:

var data = [
      [
       {name:"John", age:21, x:true},
       {name:"John", age:32, x:false}, 
       {name:"Mark", age:44, x:false}

      ],

      [
       {name:"John", age:78, x:true},
       {name:"John", age:65, x:false}, 
       {name:"Mark", age:77, x:false} 

      ],

      [
       {name:"John", age:78, x:true},
       {name:"John", age:11, x:false}, 
       {name:"Mark", age:15, x:false}, 
      ]
    ];

Any help?

share|improve this question

marked as duplicate by A1rPun, Andreas, Alexander, Teemu, Marco Demaio Jan 30 at 15:26

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

    
@A1rPun right, thanks for link – David Jan 30 at 14:40

2 Answers 2

up vote 2 down vote accepted

First create a compare() function:

function compare(a,b) {
  if (b.x) return 1;
  if (a.x) return -1;
  return 0;
}

And then sort each of the arrays using this logic:

for(var i=0,l=data.length; i<l; i++) data[i].sort(compare);

JS Fiddle demo

Edit

ScottSauyet pointed out that this method does not keep the original order between identical values. So I took a different approach, as we are not really sorting the values, but really splitting them.

It looks like this:

Array.prototype.booleanSortBy = function(property){
    var res = {true : [], false: []};
    for(var i=0, l=this.length; i<l; i++){
        res[ this[i][property] ].push( this[i] );
    }
    return res[true].concat( res[false] );
}

Check it out in JS Fiddle

Note: If this were to be used in the real world, it would need property checking. If there is something wrong passed to this function, it will fail miserably.

share|improve this answer
    
this works great, thank you – David Jan 30 at 14:40
    
I have a question. If I set this function like this: function compare(a, b) { if (b.x) return 1; } it does still work, because it always compare a to be, and if b is true (id doesn;t really matter what the a is) then it moves it one index back. Do you think it's still fine? – David Jan 30 at 19:18
    
@David Although it might seem to work in your case, it won't always work. I've tried it on sets of random data: JS Fiddle demo. Try it several times, you'll see that there is always something wrong. – blex Jan 31 at 8:09
    
@ScottSauyet, deleted my comments too, you could do the same. I may also have overreacted and perhaps not decoded your comments correctly. I agree with blex off course. – davidkonrad Feb 1 at 0:38
    
Note that this sort does do what's required, but is not stable: values that are equal according to criteria might be swapped by the sort. For instance, [A-false, B-false, C-true, D-true, E-false] will be sorted [D, C, A, B, E], swapping the order of C and D. Some of the answers in the duplicate would give you a stable sort. – Scott Sauyet Feb 2 at 16:25

The answer from blex is nearly perfect. But if you have to do this often, for sorting on different boolean fields, you might want to bring it up a level using a higher order function:

function compareOn(name) {
  return function compare(a,b) {
    if (b[name]) return 1;
    if (a[name]) return -1;
    return 0;
  };
}

var comparator = compareOn('x');

for(var i=0,l=data.length; i<l; i++) data[i].sort(comparator);

Update

blex asked what I meant about the above algorithm not yielding a stable sort. This is an attempt to clear that up. A stable sort is one in which two values that are considered equal by the sorting criteria are left in the same order they were in the original list. While this is not a requirement of the specifications, Javascript engines often have a sort that is stable so long as the sorting callback follows the rules. (Chrome has long been an exception.)

A sorting function should have certain behavior. It should accept two values and return

  • a negative number if the first value is less than the second
  • a positive number if the first value is greater than the second
  • zero if the two values are equal

This sorting function:

function (a,b) {
    if (b.x) return 1;
    if (a.x) return -1;
    return 0;
};

does not actually do that, so even in a stable-sorting environment, such as Firefox, it can return a somewhat surprising result. It doesn't meet the criteria because if both values have x: true, this function returns 1 instead of the required 0.

              Expected                        Actual
                 b.x                            b.x
             true   false                   true   false
          +-------+-------+              +-------+-------+
     true |   0   |  -1   |         true |   1   |  -1   |
a.x       +-------+-------+    a.x       +-------+-------+
    false |   1   |   0   |        false |   1   |   0   |
          +-------+-------+              +-------+-------+

The reason this works at all is that nothing has broken on the actual greater than or less than cases; those are still correct. The trouble is that cases that should be equal are not reported so. But that just means that the sort will place what should be equal into a possibly unusual order. And depending upon the sorting algorithm, it might do so in an unpredictable manner.

An untested variation of this function that avoids these issues might look like this:

function (a,b) {
    if (b.x) {
        if (a.x) return 0;
        return 1;
    }
    if (a.x) return -1;
    return 0;
};
share|improve this answer

Not the answer you're looking for? Browse other questions tagged or ask your own question.