Comparators in React Collection Helpers
January 24, 2017 ยท View on GitHub
The <Sort> Collection Helper takes a comparator as an argument. This guide explains how that works, and what's supported.
Comparators in general
A "comparator" is simply a function that examines two items, and returns a number based on the result of a comparison.
For example, a very basic comparator will sort a list of items in ascending order:
const comparator = (a, b) => {
if (a < b) {
return -1;
}
if (a > b) {
return 1;
}
if (a === b) {
return 0;
}
};
const items = [1, 3, 2, 5, 4];
items.sort(comparator);
// -> [1, 2, 3, 4, 5]
If we wanted, we could make it sort in descending order simply by inverting the logic related to 1 and -1:
const comparator = (a, b) => {
if (a < b) {
return 1;
}
if (a > b) {
return -1;
}
if (a === b) {
return 0;
}
};
const items = [1, 3, 2, 5, 4];
items.sort(comparator);
// -> [5, 4, 3, 2, 1]
Comparators in React Collection Helpers
We use comparators in much the same way:
const ascending = (a, b) => {
if (a < b) {
return -1;
}
if (a > b) {
return 1;
}
if (a === b) {
return 0;
}
};
const items = [1, 3, 2, 5, 4];
<Sort collection={items} comparator={ascending}>
{item => <span key={item}>{item}</span>}
</Sort>
/*
<div>
<span>1</span>
<span>2</span>
<span>3</span>
<span>4</span>
<span>5</span>
</div>
*/
A common pattern, especially in React development, is to sort an array of objects based on one of the object properties:
const items = [
{ id: 'a', name: 'apple', price: 1 },
{ id: 'b', name: 'banana', price: 5 },
{ id: 'c', name: 'orange', price: 1.50 },
];
const ascendingByPrice = (a, b) => {
if (a.price < b.price) {
return -1;
}
if (a.price > b.price) {
return 1;
}
if (a.price === b.price) {
return 0;
}
};
<Sort collection={items} comparator={ascendingByPrice}>
{item => <span key={item.id}>${item.price} - {item.name}</span>}
</Sort>
/*
<div>
<span>\$1 - apple</span>
<span>\$1.50 - orange</span>
<span>\$5 - banana</span>
</div>
*/
String Short-hand
Because the above pattern (sorting by an object property) is so common, you can supply a string short-hand as comparator.
Here's how the above example looks, with the short-hand:
const items = [
{ id: 'a', name: 'apple', price: 1 },
{ id: 'b', name: 'banana', price: 5 },
{ id: 'c', name: 'orange', price: 1.50 },
];
<Sort collection={items} comparator="price">
{item => <span key={item.id}>${item.price} - {item.name}</span>}
</Sort>
/*
<div>
<span>\$1 - apple</span>
<span>\$1.50 - orange</span>
<span>\$5 - banana</span>
</div>
*/
Simpler, right?
However, what if you wanted to sort descending instead of ascending? Using the function comparator you can change the logic, but using the string short-hand, you have less control.
Thankfully, you can add the descending prop to specify a descending order, when using the string short-hand:
const items = [
{ id: 'a', name: 'apple', price: 1 },
{ id: 'b', name: 'banana', price: 5 },
{ id: 'c', name: 'orange', price: 1.50 },
];
<Sort descending collection={items} comparator="price">
{item => <span key={item.id}>${item.price} - {item.name}</span>}
</Sort>
/*
<div>
<span>\$5 - banana</span>
<span>\$1.50 - orange</span>
<span>\$1 - apple</span>
</div>
*/
The descending prop has no effect when used with a function comparator.
Insert joke about how you can't compare apples and oranges here.