PDA

View Full Version : sort an array of objects in javascript



Anas
12-17-2009, 03:47 PM
Hi,
Can i sort an array of objects in javascript?.
I am having the value as

var myVarr = [{"name":"xyz","age":21},
{"name":"cde","age":25}].


The above array has two objects.
I need to sort by age using javascript.

Please help.

Regards,
anas

mrhoo
12-17-2009, 04:02 PM
myVarr.sort(function(a,b){
return a.age-b.age;
})

Array.sort can take any function you define to compare the two items.

Kor
12-17-2009, 04:18 PM
myVarr.sort(function (a,b) {return a['age'] == b['age'] ? 0 : (a['age'] < b['age'] ? -1 : 1)});

Philip M
12-17-2009, 05:18 PM
This may be of use as well:-


<script type="text/javascript">

var MyArray = [
['Peter','New York','25','artist'],
['Albert','Chicago','51','banker'],
['Rupert','Los Angeles','42','film star'],
['Michael','Boston','38','computer technician']
];

Array.prototype.multiSort = function(index){
for(var i=0; i<this.length; i++){
var temp = this[i].splice(index,1);
this[i].unshift(temp);
} return this.sort();
}

// EXAMPLE USAGE:

alert (MyArray.multiSort(0)[0]);
alert (MyArray.multiSort(0)[1]);

document.write(MyArray.multiSort(0)); // SORTS BY NAME
document.write("<br><br>")
document.write(MyArray.multiSort(1)); // SORTS BY CITY
document.write("<br><br>")
document.write(MyArray.multiSort(2)); // SORTS BY AGE
document.write("<br><br>")
document.write(MyArray.multiSort(3)); // SORTS BY OCCUPATION
document.write("<br><br>")
document.write(MyArray.multiSort(0)[2]);
document.write("<br><br>")
document.write(MyArray.multiSort(0)[2][1] + " " + MyArray.multiSort(0)[2][0]);

</script>

rnd me
12-17-2009, 11:23 PM
everyone else is doing it, why can't i?

here's a tiny reusable object sorter:

function sortBy(prop){ return function(a,b){return a[prop]-b[prop];}}

//usage:
var myVarr = [{"name":"xyz","age":29},{"name":"cde","age":25}];
myVarr.sort(sortBy("age"));

after running, myVarr === [{"name":"cde","age":25},{"name":"xyz","age":29}]

Old Pedant
12-17-2009, 11:41 PM
Note that of course using just subtraction like that only works for numeric values.

But easily adaptable to other field types:


function sortBy(prop){return function(a,b){return a[prop]>b[prop] ? 1 : a[prop]<b[prop] ? -1 : 0; }

//usage:
var myVarr = [{"name":"xyz","age":29},{"name":"cde","age":25}];
myVarr.sort(sortBy("name"));

Philip M
12-18-2009, 08:26 AM
Note that of course using just subtraction like that only works for numeric values.

But easily adaptable to other field types:


function sortBy(prop){return function(a,b){return a[prop]>b[prop] ? 1 : a[prop]<b[prop] ? -1 : 0; }

//usage:
var myVarr = [{"name":"xyz","age":29},{"name":"cde","age":25}];
myVarr.sort(sortBy("name"));


Alas, it does not work for me! :( There is a missing closing brace }, but
document.write(myVarr.sort(sortBy("name")));
gives me:-
[object Object],[object Object]
and
alert (myVarr[0][1]);
gives me "undefined".

Anas
12-18-2009, 10:06 AM
The above one worked for me.......Thank you very much....Pls use
[CODE]myVarr[0].name[CODE]

Philip M
12-18-2009, 11:42 AM
Ah, I have it now! :)


function sortBy(prop){return function(a,b){return a[prop]>b[prop] ? 1 : a[prop]<b[prop] ? -1 : 0; }}
//usage:
var myVarr = [{"name":"xyz","age":29},{"name":"cde","age":25}];
document.write (myVarr[0].name + " " + myVarr[0].age + "<br>");
myVarr.sort(sortBy("name"));
document.write (myVarr[0].name + " " + myVarr[0].age + "<br>");

But I don't see how this is any improvement on the code I posted in Post#4.

Old Pedant
12-18-2009, 07:27 PM
Yes, typos. I should know better around you guys. <grin style="sheepish" />

Old Pedant
12-18-2009, 07:54 PM
Philip: Your post #4 is very clever. Would definitely use it for several purposes.

Mine was solely a comment on the fact that RndMe's would only work for numeric fields.

Trinithis
12-19-2009, 03:18 AM
But I don't see how this is any improvement on the code I posted in Post#4.

It doesn't destroy the ordering of the object indices :D

rnd me
12-19-2009, 06:03 AM
Note that of course using just subtraction like that only works for numeric values.

yeah, i just wrote for the OP...


i guess it can be more flexible:



function sortBy(prop, type){
type=type!=null?type:Object;
if(typeof type !=="function"){type = type.constructor;}
switch(type){
case Number: return function(a,b){return a[prop]-b[prop];}
case String: return function(a,b){a=a[prop];b=b[prop];return a>b?1:(b===a?0:-1);}
case Date: return function(a,b){return a[prop].getTime()-b[prop].getTime();}
default: return function(a,b){a=a[prop]+"";b=b[prop]+"";return a>b?1:(b===a?0:-1);}
}
}//end sortBy()


/*usage: pass sortBy to an Array.sort call on an array of objects.
arguments: [0]: property to use as a sort key (string).
[1]: (optional) sort type. a constructor or an instance of a native type. default is Object */


//examples/tests:
var myVarr = [{"name":"xyz","age":29},{"name":"cde","age":25}];

myVarr.sort(sortBy("age",0)); //[{name:"cde", age:25}, {name:"xyz", age:29}]
myVarr.sort(sortBy("age",Number)); //[{name:"cde", age:25}, {name:"xyz", age:29}]
myVarr.sort(sortBy("name")); //[{name:"cde", age:25}, {name:"xyz", age:29}]
myVarr.sort(sortBy("name","")); //[{name:"cde", age:25}, {name:"xyz", age:29}]
myVarr.sort(sortBy("name",String));//[{name:"cde", age:25}, {name:"xyz", age:29}]

tested in firebug...

for speed, this function does not check for type, so don't pass it Date if you have any non-Dates at the sort key property...

mixed types can be sorted by omitting the 2nd argument, which uses the property's native .toString() value.

Old Pedant
12-20-2009, 05:02 AM
I give up. Why can't I just use:


function sortBy(prop, type){
type=type!=null?type:Object;
if(typeof type !=="function"){type = type.constructor;}
switch(type){
case Number:
case String:
case Date: return function(a,b){return a[prop]>b[prop] ? 1 : a[prop]<b[prop] ? -1; 0 );
default: return function(a,b){a=a[prop]+"";b=b[prop]+"";return a>b?1:(b===a?0:-1);}
}
}//end sortBy()

Why need there be a difference between how Number, String, and Date are executed?

And realistically, if the type is not one of those 3, then you probably need a custom sort function, anyway. Converting the object to a string like that would almost surely produce a nonsense comparison.

Example:


function foo(p,e) {
this.password = p;
this.email = e;
}

var whatever = [ { "name" : "joe", "info": new foo("xxx","a@b.com") },
{ "name": "bob", "info" : new foo("yyy","c@d.com") } ];

whatever.sort( sortBy("info",foo) );

What is that going to do that is meaninful??

The sort funcition will end up calling a compare that will compare the two strings "[object Object]" and "[object Object]" so all comparisons will be equal. (Yes, you could supply a toString() method for you ojbects, but maybe the thing they really want to be compared on is a number?)

So... I would say that if the property in question is not a standard JS data type, the coder *must* supply the custom comparison function.

rnd me
12-20-2009, 06:57 AM
I give up. Why can't I just use:


function sortBy(prop, type){
type=type!=null?type:Object;
if(typeof type !=="function"){type = type.constructor;}
switch(type){
case Number:
case String:
case Date: return function(a,b){return a[prop]>b[prop] ? 1 : a[prop]<b[prop] ? -1; 0 );
default: return function(a,b){a=a[prop]+"";b=b[prop]+"";return a>b?1:(b===a?0:-1);}
}
}//end sortBy()

Why need there be a difference between how Number, String, and Date are executed?


1. performance: a-b is faster for numbers.
2. you're right that string and number can be treated the same; thanks for pointing that out!
3. overlap: i force a .toString() on the property as it's the best way to handle an unknown type. I'll be the first to admit that it's not universal by any means.
However, it does handle RegExp, Boolean, Function, and any user-types with a sortable custom .toString().

it's written for flexibility, so if you don't want to mod your foo object, you can always define a custom sort inside of sortBy() to handle it:



function sortBy(prop, type){
type=type!=null?type:Object;
if(typeof type !=="function"){type = type.constructor;}
switch(type){
case Number: return function(a,b){return a[prop]-b[prop];}
case String: case Date:return function(a,b){a=a[prop];b=b[prop];return a>b?1:(b===a?0:-1);}

case foo: return function(a,b){a=a[prop].email;b=b[prop].email;return a>b?1:(b===a?0:-1);}

default: return function(a,b){a=a[prop]+"";b=b[prop]+"";return a>b?1:(b===a?0:-1);}
}
}//end sortBy()


function foo(p,e) {
this.password = p;
this.email = e;
}

var whatever = [ { "name" : "joe", "info": new foo("xxx","v@b.com") },
{ "name": "bob", "info" : new foo("yyy","c@d.com") } ];

whatever.sort( sortBy("info",foo) );//put's "bob's" object first...



in this case, i simply remap foo's sort to use it's email property, but fancier algos could be used the same fashion...

Trinithis
12-20-2009, 07:40 AM
I'd just as much rather have an optional parameter that is the sorting function. That way you don't need to modify other code.

As for using (-) for numbers, are there issues with Infinity or large numbers?