Is the following pattern a good way to do multiple sorts, for example something along the lines of:
ORDER BY id ASC, name DESC, date ASC
let people = [
{Name: 'Alex', Age: 20},
{Name: 'George', Age: 20},
{Name: 'Tommy', Age: 11},
];
function cmpPeople(p1, p2) {
// Age ASC
if (p1.Age != p2.Age) {
return p1.Age - p2.Age; // numeric fields can use subtraction
}
// Name DESC
else if (p1.Name != p2.Name) {
return (p1.Name > p2.Name) ? -1 : 1;
}
// Placeholder at end
else return 0;
}
people.sort(cmpPeople);
console.log(people);
If not, what might be a cleaner way to chain together multiple sorts similar to how it's communicated with SQL?
CodePudding user response:
What you have works, but here's a more succinct method perhaps. Using the arrow function, we can return a result without return
. The first comparison returns the age difference unless it's zero, in which case it returns the second comparison which uses localeCompare
let people = [{Name: 'Alex', Age: 20}, {Name: 'George', Age: 20}, {Name: 'Tommy', Age: 11}];
const cmpPeople = (p1, p2) => p1.Age - p2.Age || p2.Name.localeCompare(p1.Name)
people.sort(cmpPeople);
console.log(people);
CodePudding user response:
You could take an array of wanted keys and their order and iterate this array until a value is different from zero.
const
ASC = (a, b) => a > b || -(a < b),
DESC = (a, b) => ASC(b, a),
sortBy = columns => (a, b) => {
let r = 0;
columns.some(([key, fn]) => r = fn(a[key], b[key]));
return r;
}
people = [{ Name: 'George', Age: 20 }, { Name: 'Alex', Age: 20 }, { Name: 'Tommy', Age: 11 }],
order = [
['Age', ASC],
['Name', ASC]
];
people.sort(sortBy(order));
console.log(people);
.as-console-wrapper { max-height: 100% !important; top: 0; }
CodePudding user response:
The direction is right. The else
is redundant. Also your comparator is very specific (contains business logic), you can't reuse it. I took it as an exercise and wrote generic comparator generator.
let people = [
{ Name: "Alex", Age: 20 },
{ Name: "George", Age: 20 },
{ Name: "George", Age: 11 },
{ Name: "George", Age: 10 },
{ Name: "Tommy", Age: 11 },
];
function getComparator(fields) {
return function (p1, p2) {
for (let i = 0; i < fields.length; i ) {
const v1 = p1[fields[i].field];
const v2 = p2[fields[i].field];
// It should work for numbers & strings in same way
if (v1 > v2) return fields[i].order === "asc" ? 1 : -1;
if (v1 < v2) return fields[i].order === "asc" ? -1 : 1;
}
return 0;
};
}
const comparator = getComparator([
{ field: "Age", order: "asc" },
{ field: "Name", order: "desc" },
]);
people.sort(comparator);
console.log(people);