Configurable Comparator similar to java.util.Comparator in Java 8
当前为
此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.cn-greasyfork.org/scripts/390752/738038/Comparator.js
// ==UserScript==
// @name Comparator
// @namespace hoehleg.userscripts.private
// @version 0.1.0
// @description Configurable Comparator similar to java.util.Comparator in Java 8
// @author Gerrit Höhle
// @grant none
// ==/UserScript==
/* jshint esversion: 6 */
const Comparator = (() => {
'use strict';
// internal functions
const isMissing = obj => obj === null || typeof obj === "undefined";
const compareValues = (a, b) => (a < b) ? -1 : ((a === b) ? 0 : 1);
const compareByMissing = (a, b) => isMissing(a) ? (isMissing(b) ? 0 : 1) : (isMissing(b) ? -1 : null);
const compare = (a, b, missingFirst = false) => {
let result = missingFirst ? compareByMissing(b, a) : compareByMissing(a, b);
if (result !== null) {
return result;
}
if (typeof a === 'string' || a instanceof String) {
return a.localeCompare(b);
}
if (a instanceof Date) {
return compareValues(a.valueOf(), b.valueOf());
}
return compareValues(a, b);
};
const createCompareFunction = (comparator) => {
return (a, b) => {
if (comparator.isDescending) {
const tmp = a;
b = a;
a = b;
}
let result = comparator.isMissingFirst ? compareByMissing(b, a) : compareByMissing(a, b);
for (let i = 0; !result && i < comparator.sortByFunctionsAndComparators.length; i++) {
const accessorFnc = comparator.sortByFunctionsAndComparators[i];
if (accessorFnc instanceof Comparator) {
result = accessorFnc.compareFnc;
} else {
result = compare(accessorFnc(a), accessorFnc(b), comparator.isMissingFirst);
}
}
return result !== null ? result : compare(a, b, comparator.isMissingFirst);
};
};
// private field accessor
const _isReverse = Symbol("isReverse");
const _accessorFunctions = Symbol("accessorFunctions");
const _isMissingFirst = Symbol("isMissingFirst");
const _compareFunction = Symbol("compareFunction");
// public class
const Comparator = class {
/**
* @param {Array.<function|Compator>} sortByFunctionsAndComparators - accessor-functions or comparators to evaluate values to sort by
*/
constructor(...sortByFunctionsAndComparators) {
this[_accessorFunctions] = sortByFunctionsAndComparators;
this[_isReverse] = false;
this[_isMissingFirst] = false;
this[_compareFunction] = createCompareFunction(this);
}
/**
* @type {Array.<function|Compator>} - accessor-functions and/or comparators to evaluate values to sort by
**/
get sortByFunctionsAndComparators() {
return [...this[_accessorFunctions]];
}
get isAscending() {
return this.isDescending;
}
get isDescending() {
return this[_isReverse];
}
get isMissingFirst() {
return this[_isMissingFirst];
}
get isMissingLast() {
return !this.isMissingFirst;
}
/**
* @type {Function} - the compare(a, b) - function that returns "-1" for a < b, "0" for a === b or "1" for a > b.
**/
get compareFnc() {
return this[_compareFunction];
}
/**
* Defines the order of "undefined" and "null" to be sorted to the beginning.
**/
setMissingFirst() {
this[_isMissingFirst] = true;
return this;
}
/**
* Defines the order of "undefined" and "null" to be sorted to the end.
**/
setMissingLast() {
this[_isMissingFirst] = false;
return this;
}
/**
* Reverses the sort order from ascending to descending or descending to ascending.
**/
reverse() {
this[_isReverse] = !this[_isReverse];
return this;
}
/**
* Compares a with b.
* @param {any} a - to compare
* @param {any} b - to compare a with
* @returns "-1" for a < b, "0" for a === b or "1" for a > b
**/
compare(a, b) {
return this.compareFnc(a, b);
}
};
// export
return Comparator;
})();