Comparator

Configurable Comparator similar to java.util.Comparator in Java 8

目前为 2019-10-03 提交的版本,查看 最新版本

此脚本不应直接安装,它是供其他脚本使用的外部库。如果你需要使用该库,请在脚本元属性加入:// @require https://update.cn-greasyfork.org/scripts/390752/738038/Comparator.js

  1. // ==UserScript==
  2. // @name Comparator
  3. // @namespace hoehleg.userscripts.private
  4. // @version 0.1.0
  5. // @description Configurable Comparator similar to java.util.Comparator in Java 8
  6. // @author Gerrit Höhle
  7. // @grant none
  8. // ==/UserScript==
  9.  
  10. /* jshint esversion: 6 */
  11. const Comparator = (() => {
  12. 'use strict';
  13.  
  14. // internal functions
  15. const isMissing = obj => obj === null || typeof obj === "undefined";
  16. const compareValues = (a, b) => (a < b) ? -1 : ((a === b) ? 0 : 1);
  17. const compareByMissing = (a, b) => isMissing(a) ? (isMissing(b) ? 0 : 1) : (isMissing(b) ? -1 : null);
  18.  
  19. const compare = (a, b, missingFirst = false) => {
  20. let result = missingFirst ? compareByMissing(b, a) : compareByMissing(a, b);
  21. if (result !== null) {
  22. return result;
  23. }
  24.  
  25. if (typeof a === 'string' || a instanceof String) {
  26. return a.localeCompare(b);
  27. }
  28.  
  29. if (a instanceof Date) {
  30. return compareValues(a.valueOf(), b.valueOf());
  31. }
  32.  
  33. return compareValues(a, b);
  34. };
  35.  
  36. const createCompareFunction = (comparator) => {
  37. return (a, b) => {
  38. if (comparator.isDescending) {
  39. const tmp = a;
  40. b = a;
  41. a = b;
  42. }
  43.  
  44. let result = comparator.isMissingFirst ? compareByMissing(b, a) : compareByMissing(a, b);
  45.  
  46. for (let i = 0; !result && i < comparator.sortByFunctionsAndComparators.length; i++) {
  47. const accessorFnc = comparator.sortByFunctionsAndComparators[i];
  48.  
  49. if (accessorFnc instanceof Comparator) {
  50. result = accessorFnc.compareFnc;
  51. } else {
  52. result = compare(accessorFnc(a), accessorFnc(b), comparator.isMissingFirst);
  53. }
  54. }
  55.  
  56. return result !== null ? result : compare(a, b, comparator.isMissingFirst);
  57. };
  58. };
  59.  
  60. // private field accessor
  61. const _isReverse = Symbol("isReverse");
  62. const _accessorFunctions = Symbol("accessorFunctions");
  63. const _isMissingFirst = Symbol("isMissingFirst");
  64. const _compareFunction = Symbol("compareFunction");
  65.  
  66. // public class
  67. const Comparator = class {
  68. /**
  69. * @param {Array.<function|Compator>} sortByFunctionsAndComparators - accessor-functions or comparators to evaluate values to sort by
  70. */
  71. constructor(...sortByFunctionsAndComparators) {
  72. this[_accessorFunctions] = sortByFunctionsAndComparators;
  73. this[_isReverse] = false;
  74. this[_isMissingFirst] = false;
  75. this[_compareFunction] = createCompareFunction(this);
  76. }
  77.  
  78. /**
  79. * @type {Array.<function|Compator>} - accessor-functions and/or comparators to evaluate values to sort by
  80. **/
  81. get sortByFunctionsAndComparators() {
  82. return [...this[_accessorFunctions]];
  83. }
  84.  
  85. get isAscending() {
  86. return this.isDescending;
  87. }
  88.  
  89. get isDescending() {
  90. return this[_isReverse];
  91. }
  92.  
  93. get isMissingFirst() {
  94. return this[_isMissingFirst];
  95. }
  96.  
  97. get isMissingLast() {
  98. return !this.isMissingFirst;
  99. }
  100.  
  101. /**
  102. * @type {Function} - the compare(a, b) - function that returns "-1" for a < b, "0" for a === b or "1" for a > b.
  103. **/
  104. get compareFnc() {
  105. return this[_compareFunction];
  106. }
  107.  
  108. /**
  109. * Defines the order of "undefined" and "null" to be sorted to the beginning.
  110. **/
  111. setMissingFirst() {
  112. this[_isMissingFirst] = true;
  113. return this;
  114. }
  115.  
  116. /**
  117. * Defines the order of "undefined" and "null" to be sorted to the end.
  118. **/
  119. setMissingLast() {
  120. this[_isMissingFirst] = false;
  121. return this;
  122. }
  123.  
  124. /**
  125. * Reverses the sort order from ascending to descending or descending to ascending.
  126. **/
  127. reverse() {
  128. this[_isReverse] = !this[_isReverse];
  129. return this;
  130. }
  131.  
  132. /**
  133. * Compares a with b.
  134. * @param {any} a - to compare
  135. * @param {any} b - to compare a with
  136. * @returns "-1" for a < b, "0" for a === b or "1" for a > b
  137. **/
  138. compare(a, b) {
  139. return this.compareFnc(a, b);
  140. }
  141. };
  142.  
  143. // export
  144. return Comparator;
  145. })();