views:

486

answers:

5

Hi,

Suppose I have an array of records: [{a:0,b:0},{a:2,b:1},{a:1,b:2}] which I wish to sort in descending order of the "a" field in each record, and alert the sorted records as a new array (ie the new array would be [{a:2,b:1},{a:1,b:2},{a:0,b:0}]) - how would I go about this? I've tried a few approaches but am banging my head against the wall.

Thanks

A: 

Using closures is slower than directly referencing a function.

// assume var records = [{a:0,b:0},{a:2,b:1},{a:1,b:2}];
records.sort(myCustomSort);
function myCustomSort(a, b) {
    return (b.a - a.a);
}

If you really need a second variable for the new array, simply make a copy of the initial array prior to calling the custom sort method.

cballou
+2  A: 

A straightforward approach

var sorted = [{a:0,b:0},{a:2,b:1},{a:1,b:2}].sort( function( a, b )
{
  if ( a.a == b.a ) return 0;
  return ( a.a > b.a ) ? 1 : -1;
}).reverse();

EDIT

And a more flexible approach

// Note: console.log() require Firebug

var records = [{a:0,b:0},{a:2,b:1},{a:1,b:2}];
console.log( records );

// Sorty by 'a' ascending
sortByProperty( records, 'a' );
console.log( records );

// Sort by 'b' descending
sortByProperty( records, 'b', true );
console.log( records );  

function sortByProperty( arr, property, descending )
{
  arr.sort( function( a, b )
  {
    return Boolean( descending )
      ? b[property] - a[property]
      : a[property] - b[property]
  } );
}

EDIT 2

A version that works for strings as well

// Note: console.log() require Firebug

var records = [
    {a:0,b:0}
  , {a:2,b:1}
  , {a:'banana',b:'apple'}
  , {a:1,b:2}
  , {a:'apple',b:'banana'}
];
console.log( records );

// Sorty by 'a' ascending
sortByProperty( records, 'a' );
console.log( records );

// Sort by 'b' descending
sortByProperty( records, 'b', true );
console.log( records );  

function sortByProperty( arr, property, descending )
{
  arr.sort( function( a, b )
  {
    var c = a[property].toString()
      , d = b[property].toString()

    if ( c == d ) return 0;
    return Boolean( descending )
      ? d > c ? 1 : -1
      : d < c ? 1 : -1 
  } );
}
Peter Bailey
Added an alternate solution that allows you to specify the property to sort by and an order with parameters.
Peter Bailey
A: 

How about a sort delegate?

[{a:0,b:0},{a:2,b:1},{a:1,b:2}].sort(function(a,b){
    // see http://www.javascriptkit.com/javatutors/arraysort.shtml 
    // for an explanation of this next line
    return b.a-a.a;
});

(After saving, I noticed two other almost identical answers, but I'll leave mine here for the minor differences.)

Brother Erryn
Thanks for the reply (this applies to all three of you really!)The only problem is that it alerts "[object Object],[object Object],[object Object]" - is there any way I could convert the objects so that it alerts the array of sorted records correctly?Thanks again
Deacon
Why in the world did I get downvoted? For not immediately erasing my answer once I noticed it was a duplicate?To answer Deacon's question, well, I'd have to see exactly how you're trying to alert the results of the sort.
Brother Erryn
@Deacon - the best approach is to stop using alert() to debug and switch to something like Firebug instead.
Peter Bailey
@Peter Bailey, Firebug is awesome, as is `console.log()`, but the original questioner specifically asked for `alert()` ... maybe worth pointing out threads like http://stackoverflow.com/questions/103155/javascript-debugger to help people out.
artlung
A: 
// your items array
var items = [{a:0,b:0},{a:2,b:1},{a:1,b:2}];
// function we can use as a sort callback
var compareItemsBy_a_Descending = function(x,y) {
  return y.a - x.a;
};
// function to alert the items array
var displayItems = function(items) {
  var out = [];
  for (var i=0;i<items.length;i++) {
    out.push('{a:' + items[i].a + ',b:' + items[i].b + '}');
  }
  alert('[' +out.join(',') + ']');
};

// run it
displayItems(items);

RESULT: [{a:0,b:0},{a:2,b:1},{a:1,b:2}]

// sort it
items.sort(compareItemsBy_a_Descending);

// run it again
displayItems(items);

RESULT: [{a:2,b:1},{a:1,b:2},{a:0,b:0}]

artlung
Thank you very much! Much obliged
Deacon
A: 

Hughes my colleague just showed me today the following.
Note the use of -cmp() and cmp() for descending and ascending.

var cmp = function(x, y){ return x > y? 1 : x < y ? -1 : 0; },
    arr =  [{a:0,b:0},{a:2,b:1},{a:1,b:2},{a:2, b:2}];

// a ascending
arr.sort(function(x, y){
    return cmp(x.a, y.a) < cmp(y.a, x.a) ? -1:1;
});

// a descending
arr.sort(function(x, y){
    return -cmp(x.a, y.a) < -cmp(y.a, x.a) ? -1:1;
});

// a ascending, b descending
arr.sort(function(x, y){
    return [cmp(x.a, y.a), -cmp(x.b, y.b)] < [cmp(y.a, x.a), -cmp(y.b,x.b)] ? -1:1;
});
Mic