Skip to content

Instantly share code, notes, and snippets.

@joelpurra
Created June 24, 2012 20:17
Show Gist options
  • Save joelpurra/2984763 to your computer and use it in GitHub Desktop.
Save joelpurra/2984763 to your computer and use it in GitHub Desktop.
A javascript plugin to create a comparator for one or more properties of an object. Comparators are useful for sorting arrays of objects, and for general comparisons in, for example, if statements. The comparison is done only if the types of both objects'
/*!
* @license ObjectComparator
* Copyright © 2012 Joel Purra <http://joelpurra.se/>
* Released under MIT, BSD and GPL license. Comply with at least one.
*
* A javascript plugin to create a comparator for one or more properties of an object.
* Comparators are useful for sorting arrays of objects, and for general comparisons
* in, for example, if statements.
* The comparison is done only if the types of both objects' property matches.
*/
// https://gist.github.com/2984763
//
// USAGE
// var comparator = JoelPurra.createComparator("propertyName");
// var reverseComparator = JoelPurra.createComparator("!propertyName");
// var comparators = JoelPurra.createComparators(["propertyName1", "propertyName2"]);
// var mixedComparators = JoelPurra.createComparators(["propertyName1", "!propertyName2"]);
// EXAMPLE
// var people = [
// // Age in years, length in centimeters
// { name: "John", age: 30, height: 187 },
// { name: "Bilbo", age: 111, height: 112 },
// { name: "Jane", age: 30, height: 165 },
// { name: "Gollum", age: 570, height: 112 }
// ];
// // Sort by height (ascending) only
// var shortToLongComparator = JoelPurra.createComparator("height");
// people.sort(shortToLongComparator);
// // => Bilbo, Gollum, Jane, John
// // Sort by height (ascending) and age (descending)
// var shortToLongOldToYoungComparator = JoelPurra.createComparators(["height", "!age"]);
// people.sort(shortToLongOldToYoungComparator);
// => Gollum, Bilbo, Jane, John
//
/*jslint white: true*/
// Set up namespace, if needed
var JoelPurra = JoelPurra || {};
(function(namespace) {
"use strict"; // jshint ;_;
namespace.createNormalComparator = function(property) {
// This comparison is not as relaxed as normal comparisons. The type is checked first, and it has
// to match in order to continue.
//
// https://developer.mozilla.org/en/JavaScript/Guide/Expressions_and_Operators#Comparison_operators
// "The operands can be numerical, string, logical, or object values.
// Strings are compared based on standard lexicographical ordering, using Unicode values.
// In most cases, if the two operands are not of the same type, JavaScript attempts to convert
// the operands to an appropriate type for the comparison."
return function(a, b) {
if (typeof(a) !== typeof(b)) {
throw new Error("object property \"" + property + "\" was not of the same type in a and b.");
}
// Using strict comparison now that the object types are the same
if (a[property] === b[property]) {
return 0;
}
if (a[property] < b[property]) {
return -1;
}
if (a[property] > b[property]) {
return 1;
}
throw new Error("Could not compare objects and find a matching result");
};
};
namespace.createReverseComparator = function(property) {
// Calling the parent function actually allows for properties like
// "!!age" for "reverse reverse age comparator" ;)
var comparator = namespace.createComparator(property);
return function(a, b) {
return comparator(b, a);
};
};
namespace.createComparator = function(property) {
var comparator;
if (property.substring(0, 1) === "!") {
property = property.substring(1);
comparator = namespace.createReverseComparator(property);
} else {
comparator = namespace.createNormalComparator(property);
}
return comparator;
};
namespace.createComparators = function(properties) {
var comparators = [],
i;
for (i = 0; i < properties.length; i += 1) {
comparators.push(namespace.createComparator(properties[i]));
}
return function(a, b) {
var result = 0,
i, comparator;
for (i = 0; i < comparators.length; i += 1) {
comparator = comparators[i];
result = comparator(a, b);
if (result !== 0) {
break;
}
}
return result;
};
};
}(JoelPurra));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment