Reputation: 21150
I have a large-ish dataset (from 400 - 4,000 objects stored in an array), and I'm trying to filter them by a user-selected field.
Right now I'm using this function, found on another SO question:
var sort = function (prop, arr) {
prop = prop.split('.');
var len = prop.length;
arr.sort(function (a, b) {
var i = 0;
while( i < len ) {
a = a[prop[i]];
b = b[prop[i]];
i++;
}
if (a < b) {
return -1;
} else if (a > b) {
return 1;
} else {
return 0;
}
});
return arr;
};
Sample data - I want to sort the objects by the friends
count:
var data = [
{
name: 'Jim',
friends: {
count: 20,
url: 'http://foo.com'
}
},{
name: 'Lucy',
},{
name: 'Phil',
friends: {
count: 450,
url: 'http://moo.com'
}
}
];
Notice how "Lucy" doesn't have a friends
object - so when I run sort('friends.count', data);
, the script breaks.
Ideally I'd like the objects which don't have the property that I'm sorting by to be put at the end of the array. Any ideas on how this can be achieved?
Upvotes: 1
Views: 3732
Reputation: 214969
For example,
var data = [
{
name: 'Jim',
friends: {
count: 20,
url: 'http://foo.com'
}
},{
name: 'Lucy',
},{
name: 'Phil',
friends: {
count: 450,
url: 'http://moo.com'
}
}
];
safeGet = function(obj, prop, defaultValue) {
try {
return obj[prop]
} catch(e) {
return defaultValue
}
}
data.sort(function(x, y) {
return (
safeGet(x.friends, 'count', Infinity) -
safeGet(y.friends, 'count', Infinity));
});
document.write("<pre>" + JSON.stringify(data,0,3));
If the whole property chain (friends.count
) is dynamic, change safeGet
so that it iterates the list of props:
var data = [
{
name: 'Jim',
friends: {
count: 20,
url: 'http://foo.com'
}
},{
name: 'Lucy',
},{
name: 'Phil',
friends: {
count: 450,
url: 'http://moo.com'
}
}
];
safeGet = function(obj, props, defaultValue) {
try {
return props.split('.').reduce(function(obj, p) {
return obj[p];
}, obj);
} catch(e) {
return defaultValue
}
}
data.sort(function(x, y) {
return (
safeGet(x, 'friends.count', Infinity) -
safeGet(y, 'friends.count', Infinity));
});
document.write("<pre>" + JSON.stringify(data,0,3));
If you want people with no friends to go first, not last, change Infinity
to -Infinity
.
Upvotes: 3
Reputation: 2308
Your function can be modified to check for the existence of a property:
var sort = function (prop, arr) {
prop = prop.split('.');
var len = prop.length;
arr.sort(function (a, b) {
var i = 0;
var key;
while( i < len ) {
key = prop[i];
if(!a.hasOwnProperty(key)) return 1;
if(!b.hasOwnProperty(key)) return -1;
a = a[key];
b = b[key];
i++;
}
if (a < b) {
return -1;
} else if (a > b) {
return 1;
} else {
return 0;
}
});
return arr;
};
This way it will be working. I made a jsbin for the example.
@georg's answer wouldn't work with property selected dynamically.
Upvotes: 1