Linqable/lib

View on GitHub
src/Base/BaseLinqable.ts

Summary

Maintainability
F
1 wk
Test Coverage
import aggregate, { aggregateDelegate } from '../core/aggregate';
import { InvalidOperationError } from "../error";
import { LinqArrayIterable } from "./iterable";
import { Behaviour } from './behaviour';
import where from '../core/where';
import any from '../core/any';

export class BaseLinqable<T> extends Behaviour<T> {
    /**
     * Returns the only element of a sequence,
     * and throws an exception if there is not exactly one element in the sequence.
     * @throws {InvalidOperationError} The input sequence is empty. || The input sequence contains more than one element.
     */
    public Single(): T {
        this.checkArray();
        if (this.IsEmpty())
            throw new InvalidOperationError("The input sequence is empty.");
        if (this.Count() > 1)
            throw new InvalidOperationError("The input sequence contains more than one element.");
        return this.First();
    }
    public SingleOrDefault(defaultValue: T): T {
        this.checkArray();
        try {
            return this.Single();
        }
        catch (e) {
            return defaultValue;
        }
    }
    public Except(arr: Array<T> | number, comparer?: (x: T, y: T) => boolean) {
        let array: Array<T>;
        let element: T = null;
        comparer = comparer || this.EqualityComparer;
        if (!(arr instanceof Array))
            element = this.array[<number>arr];
        else
            array = arr;
        var l = this.Count();
        var res = [];
        for (var i = 0; i < l; i++) {
            var t = false;
            if (element != null) {
                if (comparer(this.array[i], element) === true) {
                    t = true;
                    break;
                }
            }
            else {
                var k = array.Count();
                while (k-- > 0) {
                    if (comparer(this.array[i], array[k]) === true) {
                        t = true;
                        break;
                    }
                }
            }
            if (!t) res.push(this.array[i]);
        }
        return res;

    }
    public Zip<T3, T4>(arr: Array<T4>, selector: (x: T, y: T4) => T3): T3[] {
        return this
            .Take(Math.min(this.Count(), arr.Count()))
            .Select((t, i) => {
                return selector(t, arr[i]);
            });
    }
    public Union(arr: Array<T>): T[] {
        this.checkArray();
        return new BaseLinqable(this.array.concat(arr)).Distinct();
    }
    public Distinct(comparer?: (x: T, y: T) => boolean): Array<T> {
        this.checkArray();
        comparer = comparer || this.EqualityComparer;
        var arr = [] as Array<any>;
        var l = this.Count();
        for (var i = 0; i < l; i++) {
            if (!arr.Contains(this.array[i], comparer))
                arr.push(this.array[i]);
        }
        return arr;
    }
    public Contains(el: T, comparer?: (x: T, y: T) => boolean) {
        this.checkArray();
        comparer = comparer || this.EqualityComparer;
        var l = this.Count();
        while (l-- > 0)
            if (comparer(this.array[l], el) === true) return true;
        return false;
    }
    public Count(predicate?: (element: T, index?: number) => boolean) {
        this.checkArray();
        if (!predicate)
            return this.array.length;
        return this.Where(predicate).ToArray().length;
    }
    public IsEmpty(): boolean {
        this.checkArray();
        return this.array.length == 0;
    }
    public All(predicate: (element: T) => boolean, context?: any): boolean {
        predicate = predicate || (() => true);
        let l = this.array.length;
        return this.Where(predicate, context).length == l;
    }
    public Max(selector?: (element: T) => number): number {
        this.checkArray();
        var l = this.array.length;
        if (l == 0)
            return 0;
        selector = selector || <(element: T) => number><any>this.Selector;
        var max = selector(this.array[0]);
        if (typeof max !== "number")
            throw new InvalidOperationError("Element is not number.");
        while (l-- > 0)
            if (selector(this.array[l]) > max && isFinite(selector(this.array[l]))) max = selector(this.array[l]);
        return max;
    }
    public Min(selector?: (element: T) => number): number {
        this.checkArray();
        var l = this.array.length;
        if (l == 0)
            return 0;
        selector = selector || <(element: T) => number><any>this.Selector;
        var min = selector(this.array[0]);
        if (typeof min !== "number")
            throw new InvalidOperationError("Element is not number.");
        while (l-- > 0)
            if (selector(this.array[l]) < min && isFinite(selector(this.array[l]))) min = selector(this.array[l]);
        return min;
    }
    public MaxBy(selector: (element: T) => number): T {
        this.checkArray();
        var l = this.array.length;
        if (l == 0)
            throw new InvalidOperationError("Array Is Empty.");
        selector = selector || <(element: T) => number><any>this.Selector;
        var max = selector(this.array[0]);
        let FindedElement = this.array[0] as T;
        if (typeof max !== "number")
            throw new InvalidOperationError("Element is not number.");
        while (l-- > 0)
            if (selector(this.array[l]) > max && isFinite(selector(this.array[l]))) {
                max = selector(this.array[l]);
                FindedElement = this.array[l];
            }
        return FindedElement;
    }
    public MinBy(selector: (element: T) => number): T {
        this.checkArray();
        var l = this.array.length;
        if (l == 0)
            throw new InvalidOperationError("Array Is Empty.");
        selector = selector || <(element: T) => number><any>this.Selector;
        var min = selector(this.array[0]);
        let FindedElement = this.array[0] as T;
        if (typeof min !== "number")
            throw new InvalidOperationError("Element is not number.");
        while (l-- > 0)
            if (selector(this.array[l]) < min && isFinite(selector(this.array[l]))) {
                min = selector(this.array[l]);
                FindedElement = this.array[l];
            }
        return FindedElement;
    }
    public Sum(selector?: (element: T) => number, context?: any): number {
        this.checkArray();
        let num: number = 0;
        let arr: Array<number>;
        if (selector)
            arr = this.array.Select(selector, context) as any as Array<number>;
        else
            arr = this.array as any as Array<number>;

        arr.forEach(element => {
            if (typeof element !== "number")
                throw new InvalidOperationError("Element is not number.");
            if (!isFinite(element) || isNaN(element)) { }
            else
                num += element;
        });

        return num;
    }
    public Last(predicate?: (element: T, index?: number) => boolean, context?: any): T {
        this.checkArray();
        var qwe = this._reverseArray(this.array);
        for (const source of qwe) {
            if (!predicate)
                return source;
            if (predicate(source)) {
                return source;
            }
        }
        throw new InvalidOperationError("No math")
    }
    public LastOrDefault(predicate?: (element: T, index: number) => boolean, defaultValue?: T, context?: any): T {
        this.checkArray();
        try {
            return this.Where(predicate, context).First(null, context);
        }
        catch (e) {
            return defaultValue;
        }
    }
    public Take(count: number): T[] {
        if (!count)
            count = 1;
        return this.array.slice(0, count);
    }
    public First(predicate?: (element: T, index?: number) => boolean, context?: any): T {
        this.checkArray();
        console.time()
        for (const source of this.array) {
            if (!predicate)
                return source;

            if (predicate(source)) {
                return source;
            }
        }
        throw new InvalidOperationError("No math")
    }
    public FirstOrDefault(predicate?: (element: T, index: number) => boolean, def?: T, context?: any): T {
        this.checkArray();
        try {
            return this.Where(predicate, context).First(null, context);
        }
        catch (e) {
            return def;
        }
    }
    public Where(predicate: (element: T, index?: number) => boolean, context?: any): T[] {
        return where(this.array, predicate);
    }
    public Any(predicate?: (element: T) => boolean, context?: any): boolean {
        return any(this.array, predicate);
    }
    public SelectMany<TCollection, TResult>(colSelector: (element: T, index?: number) => TCollection[], resSelector: (outer: T, inner: TCollection) => TResult): Array<TResult> {
        resSelector = resSelector || function <TCollection, TResult>(outer: T, res: TCollection): TResult {
            return res as any as TResult;
        };
        return this.Aggregate((a, b) => {
            return (a as any as Array<any>).concat(colSelector(b).Select((res) => {
                return resSelector(b, res);
            }));
        }, new Array<T>());
    }
    public ThenBy<TResult>(selector: (element: T) => TResult, Comparer?: (a: TResult, b: TResult) => number): T[] {
        this.checkArray();
        Comparer = Comparer || this.SortComparer;
        var arr = this.array.slice(0);
        var fn = (a: T, b: T) => {
            return Comparer(selector(a), selector(b));
        };
        return new BaseLinqable(arr).OrderBy(this.Selector, function (a, b) {
            var res = fn(a, b);
            return res === 0 ? Comparer(selector(a), selector(b)) : res;
        });
    }
    public ThenByDescending<TResult>(selector: (element: T) => TResult, Comparer?: (a: TResult, b: TResult) => number): T[] {
        this.checkArray();
        Comparer = Comparer || this.SortComparer;
        var arr = this.array.slice(0);
        var fn = (a: T, b: T) => {
            return Comparer(selector(a), selector(b));
        };
        return new BaseLinqable(arr).OrderBy(this.Selector, function (a, b) {
            var res = fn(a, b);
            return res === 0 ? -Comparer(selector(a), selector(b)) : res;
        });
    }
    public OrderBy<TResult>(selector?: (element: T) => TResult, Comparer?: (a: TResult, b: TResult) => number): T[] {
        this.checkArray();
        selector = selector || this.Selector;
        Comparer = Comparer || this.SortComparer;
        var arr = this.array.slice(0);
        var fn = (a: T, b: T) => {
            return Comparer(selector(a), selector(b));
        };
        return arr.sort(fn);
    }
    public OrderByDescending<TResult>(selector?: (element: T) => TResult, Comparer?: (a: TResult, b: TResult) => number): T[] {
        this.checkArray();
        selector = selector || this.Selector;
        Comparer = Comparer || this.SortComparer;
        var arr = this.array.slice(0);
        var fn = (a: T, b: T) => {
            return -Comparer(selector(a), selector(b));
        };
        return arr.sort(fn);
    }
    public Aggregate<TResult>(selector: aggregateDelegate<T, TResult>, seed?: TResult): TResult {
        return aggregate(this.array, selector, seed);
    }

}