Comparator

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

Version vom 03.10.2019. Aktuellste Version

Dieses Skript sollte nicht direkt installiert werden. Es handelt sich hier um eine Bibliothek für andere Skripte, welche über folgenden Befehl in den Metadaten eines Skriptes eingebunden wird // @require https://update.greasyfork.org/scripts/390752/738038/Comparator.js

Du musst eine Erweiterung wie Tampermonkey, Greasemonkey oder Violentmonkey installieren, um dieses Skript zu installieren.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

Sie müssten eine Skript Manager Erweiterung installieren damit sie dieses Skript installieren können

(Ich habe schon ein Skript Manager, Lass mich es installieren!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==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;
})();