Comparator

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

当前为 2019-10-23 提交的版本,查看 最新版本

此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.cn-greasyfork.org/scripts/390752/743392/Comparator.js

  1. // ==UserScript==
  2. // @name Comparator
  3. // @namespace hoehleg.userscripts.private
  4. // @version 0.4
  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. /**
  20. * Basic compare function
  21. * @param {*} a - Object or value to compare
  22. * @param {*} b - Object or value to which to compare
  23. * @param {boolean} [missingFirst=false] - order of "undefined" and "null". true = first, false = last.
  24. * @returns "-1" for a < b, "0" for a === b or "1" for a > b
  25. **/
  26. const compare = (a, b, missingFirst = false) => {
  27. let result = missingFirst ? compareByMissing(b, a) : compareByMissing(a, b);
  28. if (result !== null) {
  29. return result;
  30. }
  31.  
  32. if (typeof a === 'string' || a instanceof String) {
  33. return a.localeCompare(b);
  34. }
  35.  
  36. return compareValues(a, b);
  37. };
  38.  
  39. /**
  40. * Creates the compare-function bound to a Comparator.
  41. * @param {Comparator} cmparator - the Comparator the compare - function should belong to
  42. * @returns {Function} the compare(a, b) - function
  43. */
  44. const createCompareFunction = (comparator) => {
  45. /**
  46. * Compare function bound to a comparator.
  47. * When executed the current setup of the comparator is considered
  48. * @param {*} a - Object or value to compare
  49. * @param {*} b - Object or value to which to compare
  50. **/
  51. return (a, b) => {
  52. if (comparator.isAscending) {
  53. const tmp = a;
  54. a = b;
  55. b = tmp;
  56. }
  57.  
  58. let result = comparator.isMissingFirst ? compareByMissing(b, a) : compareByMissing(a, b);
  59.  
  60. for (let i = 0; !result && i < comparator.sortByFunctionsAndComparators.length; i++) {
  61. const accessorFnc = comparator.sortByFunctionsAndComparators[i];
  62.  
  63. if (accessorFnc instanceof Comparator) {
  64. result = accessorFnc.compare(a, b);
  65. } else {
  66. result = compare(accessorFnc(a), accessorFnc(b), comparator.isMissingFirst);
  67. }
  68. }
  69.  
  70. return result !== null ? result : compare(a, b, comparator.isMissingFirst);
  71. };
  72. };
  73.  
  74. // private field accessor
  75. const _isReverse = Symbol("isReverse");
  76. const _accessorFunctions = Symbol("accessorFunctions");
  77. const _isMissingFirst = Symbol("isMissingFirst");
  78. const _compareFunction = Symbol("compareFunction");
  79.  
  80. // export class
  81. return class Comparator {
  82. /**
  83. * @param {Array.<function|Compator>} sortByFunctionsAndComparators - accessor-functions or comparators to evaluate values to sort by
  84. */
  85. constructor(...sortByFunctionsAndComparators) {
  86. this[_accessorFunctions] = sortByFunctionsAndComparators;
  87. this[_isReverse] = false;
  88. this[_isMissingFirst] = false;
  89. this[_compareFunction] = createCompareFunction(this);
  90. }
  91.  
  92. /**
  93. * @type {Array.<function|Compator>} - accessor-functions and/or comparators to evaluate values to sort by
  94. **/
  95. get sortByFunctionsAndComparators() {
  96. return [...this[_accessorFunctions]];
  97. }
  98.  
  99. get isAscending() {
  100. return this[_isReverse];
  101. }
  102.  
  103. get isDescending() {
  104. return !this.isAscending;
  105. }
  106.  
  107. get isMissingFirst() {
  108. return this[_isMissingFirst];
  109. }
  110.  
  111. get isMissingLast() {
  112. return !this.isMissingFirst;
  113. }
  114.  
  115. /**
  116. * @type {Function} - the compare(a, b) - function that returns "-1" for a < b, "0" for a === b or "1" for a > b.
  117. * the funtion is setup by this Comparator
  118. **/
  119. get compareFnc() {
  120. return this[_compareFunction];
  121. }
  122.  
  123. /**
  124. * Defines that "undefined" and "null" gets sorted to the begin
  125. **/
  126. setMissingFirst() {
  127. this[_isMissingFirst] = true;
  128. return this;
  129. }
  130.  
  131. /**
  132. * Defines that "undefined" and "null" gets sorted to the end
  133. **/
  134. setMissingLast() {
  135. this[_isMissingFirst] = false;
  136. return this;
  137. }
  138.  
  139. /**
  140. * Reverses the sort order from ascending to descending and vice versa
  141. **/
  142. reverse() {
  143. this[_isReverse] = !this[_isReverse];
  144. return this;
  145. }
  146.  
  147. /**
  148. * Compares an object or value to another considering the setup of this Comparator
  149. * @param {*} a - Object or value to compare
  150. * @param {*} b - Object or value to compare by
  151. * @returns "-1" for a < b, "0" for a === b or "1" for a > b
  152. **/
  153. compare(a, b) {
  154. return this.compareFnc(a, b);
  155. }
  156. /**
  157. * Compares an object or value to another one
  158. * @param {*} a - Object or value to compare
  159. * @param {*} b - Object or value to compare by
  160. * @param {boolean} [missingFirst=false] - order of "undefined" and "null". true = first, false = last.
  161. * @returns "-1" for a < b, "0" for a === b or "1" for a > b
  162. **/
  163. static compare(a, b, missingFirst = false) {
  164. return compare(a, b, missingFirst);
  165. }
  166. }
  167. })();