linqcontainers
Version:
Linq-Collections (ES5): [IEnumerable, IQueryable, ...] + [List, Dictionary, Stack, ... + readonly]
755 lines • 28.4 kB
JavaScript
"use strict";
// -
// Created by Ivan Sanz (@isc30)
// Copyright © 2017 Ivan Sanz Carasa. All rights reserved.
// -
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
var Collections_1 = require("./Collections");
var Iterators_1 = require("./Iterators");
var Comparers_1 = require("./Comparers");
var Utils_1 = require("./Utils");
// endregion
// region EnumerableBase
var EnumerableBase = /** @class */ (function () {
function EnumerableBase(source) {
this.source = source;
}
EnumerableBase.prototype.reset = function () {
this.source.reset();
};
EnumerableBase.prototype.next = function () {
return this.source.next();
};
EnumerableBase.prototype.asEnumerable = function () {
return this;
};
EnumerableBase.prototype.toArray = function () {
var result = [];
this.reset();
while (this.next()) {
result.push(this.value());
}
return result;
};
EnumerableBase.prototype.toList = function () {
return new Collections_1.List(this.toArray());
};
EnumerableBase.prototype.toDictionary = function (keySelector, valueSelector) {
return Collections_1.Dictionary.fromArray(this.toArray(), keySelector, valueSelector);
};
EnumerableBase.prototype.count = function (predicate) {
if (predicate !== undefined) {
// Don't copy iterators
return new ConditionalEnumerable(this, predicate).count();
}
var result = 0;
this.reset();
while (this.next()) {
++result;
}
// tslint:disable-next-line:no-bitwise
return result >>> 0;
};
EnumerableBase.prototype.any = function (predicate) {
if (predicate !== undefined) {
// Don't copy iterators
return new ConditionalEnumerable(this, predicate).any();
}
this.reset();
return this.next();
};
EnumerableBase.prototype.all = function (predicate) {
this.reset();
while (this.next()) {
if (!predicate(this.value())) {
return false;
}
}
return true;
};
EnumerableBase.prototype.reverse = function () {
return new ReverseEnumerable(this.copy());
};
EnumerableBase.prototype.contains = function (element) {
return this.any(function (e) { return e === element; });
};
EnumerableBase.prototype.where = function (predicate) {
return new ConditionalEnumerable(this.copy(), predicate);
};
EnumerableBase.prototype.select = function (selector) {
return new TransformEnumerable(this.copy(), selector);
};
EnumerableBase.prototype.selectMany = function (selector) {
var selectToEnumerable = function (e) {
var ie = selector(e);
return Array.isArray(ie)
? new ArrayEnumerable(ie)
: ie.asEnumerable();
};
return this
.select(selectToEnumerable).toArray()
.reduce(function (p, c) { return new ConcatEnumerable(p, c); }, Enumerable.empty());
};
EnumerableBase.prototype.concat = function (other) {
var others = [];
for (var _i = 1; _i < arguments.length; _i++) {
others[_i - 1] = arguments[_i];
}
var asEnumerable = function (e) {
return Array.isArray(e)
? new ArrayEnumerable(e)
: e.asEnumerable();
};
var result = new ConcatEnumerable(this.copy(), asEnumerable(other).copy());
for (var i = 0, end = others.length; i < end; ++i) {
result = new ConcatEnumerable(result, asEnumerable(others[i]).copy());
}
return result;
};
EnumerableBase.prototype.elementAt = function (index) {
var element = this.elementAtOrDefault(index);
if (element === undefined) {
throw new Error("Out of bounds");
}
return element;
};
EnumerableBase.prototype.elementAtOrDefault = function (index) {
if (index < 0) {
throw new Error("Negative index is forbiden");
}
this.reset();
var currentIndex = -1;
while (this.next()) {
++currentIndex;
if (currentIndex === index) {
break;
}
}
if (currentIndex !== index) {
return undefined;
}
return this.value();
};
EnumerableBase.prototype.except = function (other) {
return this.where(function (e) { return !other.contains(e); });
};
EnumerableBase.prototype.first = function (predicate) {
var element;
if (predicate !== undefined) {
element = this.firstOrDefault(predicate);
}
else {
element = this.firstOrDefault();
}
if (element === undefined) {
throw new Error("Sequence contains no elements");
}
return element;
};
EnumerableBase.prototype.firstOrDefault = function (predicate) {
if (predicate !== undefined) {
// Don't copy iterators
return new ConditionalEnumerable(this, predicate).firstOrDefault();
}
this.reset();
if (!this.next()) {
return undefined;
}
return this.value();
};
EnumerableBase.prototype.forEach = function (action) {
this.reset();
for (var i = 0; this.next(); ++i) {
action(this.value(), i);
}
};
EnumerableBase.prototype.groupBy = function (keySelector, valueSelector) {
var array = this.toArray();
var dictionary = new Collections_1.Dictionary();
for (var i = 0; i < array.length; ++i) {
var key = keySelector(array[i]);
var value = valueSelector !== undefined
? valueSelector(array[i])
: array[i];
if (!dictionary.containsKey(key)) {
dictionary.set(key, new Collections_1.List());
}
dictionary.get(key).push(value);
}
return dictionary.asEnumerable();
};
EnumerableBase.prototype.last = function (predicate) {
var element;
if (predicate !== undefined) {
element = this.lastOrDefault(predicate);
}
else {
element = this.lastOrDefault();
}
if (element === undefined) {
throw new Error("Sequence contains no elements");
}
return element;
};
EnumerableBase.prototype.lastOrDefault = function (predicate) {
if (predicate !== undefined) {
// Don't copy iterators
return new ConditionalEnumerable(this, predicate).lastOrDefault();
}
var reversed = new ReverseEnumerable(this);
reversed.reset();
if (!reversed.next()) {
return undefined;
}
return reversed.value();
};
EnumerableBase.prototype.single = function (predicate) {
var element;
if (predicate !== undefined) {
element = this.singleOrDefault(predicate);
}
else {
element = this.singleOrDefault();
}
if (element === undefined) {
throw new Error("Sequence contains no elements");
}
return element;
};
EnumerableBase.prototype.singleOrDefault = function (predicate) {
if (predicate !== undefined) {
// Don't copy iterators
return new ConditionalEnumerable(this, predicate).singleOrDefault();
}
this.reset();
if (!this.next()) {
return undefined;
}
var element = this.value();
if (this.next()) {
throw new Error("Sequence contains more than 1 element");
}
return element;
};
EnumerableBase.prototype.distinct = function (keySelector) {
return new UniqueEnumerable(this.copy(), keySelector);
};
EnumerableBase.prototype.aggregate = function (aggregator, initialValue) {
var value = initialValue;
this.reset();
if (initialValue === undefined) {
if (!this.next()) {
throw new Error("Sequence contains no elements");
}
value = aggregator(value, this.value());
}
while (this.next()) {
value = aggregator(value, this.value());
}
return value;
};
EnumerableBase.prototype.min = function (selector) {
if (selector !== undefined) {
// Don't copy iterators
return new TransformEnumerable(this, selector).min();
}
return this.aggregate(function (previous, current) {
return (previous !== undefined && previous < current)
? previous
: current;
});
};
EnumerableBase.prototype.orderBy = function (keySelector, comparer) {
return new OrderedEnumerable(this.copy(), Comparers_1.createComparer(keySelector, true, comparer));
};
EnumerableBase.prototype.orderByDescending = function (keySelector) {
return new OrderedEnumerable(this.copy(), Comparers_1.createComparer(keySelector, false, undefined));
};
EnumerableBase.prototype.max = function (selector) {
if (selector !== undefined) {
// Don't copy iterators
return new TransformEnumerable(this, selector).max();
}
return this.aggregate(function (previous, current) {
return (previous !== undefined && previous > current)
? previous
: current;
});
};
EnumerableBase.prototype.sum = function (selector) {
return this.aggregate(function (previous, current) { return previous + selector(current); }, 0);
};
EnumerableBase.prototype.average = function (selector) {
this.reset();
if (!this.next()) {
throw new Error("Sequence contains no elements");
}
var sum = 0;
var count = 0;
do {
sum += selector(this.value());
++count;
} while (this.next());
return sum / count;
};
EnumerableBase.prototype.skip = function (amount) {
return new RangeEnumerable(this.copy(), amount, undefined);
};
EnumerableBase.prototype.take = function (amount) {
return new RangeEnumerable(this.copy(), undefined, amount);
};
EnumerableBase.prototype.union = function (other) {
return new UniqueEnumerable(this.concat(other));
};
return EnumerableBase;
}());
exports.EnumerableBase = EnumerableBase;
// endregion
// region Enumerable
var Enumerable = /** @class */ (function (_super) {
__extends(Enumerable, _super);
function Enumerable(source) {
var _this = _super.call(this, source) || this;
_this.currentValue = new Utils_1.Cached();
return _this;
}
Enumerable.fromSource = function (source) {
if (Array.isArray(source)) {
return new ArrayEnumerable(source);
}
return new Enumerable(source);
};
Enumerable.empty = function () {
return Enumerable.fromSource([]);
};
Enumerable.range = function (start, count, ascending) {
if (ascending === void 0) { ascending = true; }
if (count < 0) {
throw new Error("Count must be >= 0");
}
var source = new Array(count);
if (ascending) {
// tslint:disable-next-line:curly
for (var i = 0; i < count; source[i] = start + (i++))
;
}
else {
// tslint:disable-next-line:curly
for (var i = 0; i < count; source[i] = start - (i++))
;
}
return new ArrayEnumerable(source);
};
Enumerable.repeat = function (element, count) {
if (count < 0) {
throw new Error("Count must me >= 0");
}
var source = new Array(count);
for (var i = 0; i < count; ++i) {
source[i] = element;
}
return new ArrayEnumerable(source);
};
Enumerable.prototype.copy = function () {
return new Enumerable(this.source.copy());
};
Enumerable.prototype.value = function () {
if (!this.currentValue.isValid()) {
this.currentValue.value = this.source.value();
}
return this.currentValue.value;
};
Enumerable.prototype.reset = function () {
_super.prototype.reset.call(this);
this.currentValue.invalidate();
};
Enumerable.prototype.next = function () {
this.currentValue.invalidate();
return _super.prototype.next.call(this);
};
return Enumerable;
}(EnumerableBase));
exports.Enumerable = Enumerable;
// endregion
// region ConditionalEnumerable
var ConditionalEnumerable = /** @class */ (function (_super) {
__extends(ConditionalEnumerable, _super);
function ConditionalEnumerable(source, predicate) {
var _this = _super.call(this, source) || this;
_this._predicate = predicate;
return _this;
}
ConditionalEnumerable.prototype.copy = function () {
return new ConditionalEnumerable(this.source.copy(), this._predicate);
};
ConditionalEnumerable.prototype.next = function () {
var hasValue;
do {
hasValue = _super.prototype.next.call(this);
} while (hasValue && !this._predicate(this.value()));
return hasValue;
};
return ConditionalEnumerable;
}(Enumerable));
exports.ConditionalEnumerable = ConditionalEnumerable;
// endregion
// region ConcatEnumerable
var ConcatEnumerable = /** @class */ (function (_super) {
__extends(ConcatEnumerable, _super);
function ConcatEnumerable(left, right) {
var _this = _super.call(this, left) || this;
_this._otherSource = right;
_this._isFirstSourceFinished = false;
return _this;
}
ConcatEnumerable.prototype.copy = function () {
return new ConcatEnumerable(this.source.copy(), this._otherSource.copy());
};
ConcatEnumerable.prototype.reset = function () {
this.source.reset();
this._otherSource.reset();
this._isFirstSourceFinished = false;
this.currentValue.invalidate();
};
ConcatEnumerable.prototype.next = function () {
this.currentValue.invalidate();
var hasValue = !this._isFirstSourceFinished
? this.source.next()
: this._otherSource.next();
if (!hasValue && !this._isFirstSourceFinished) {
this._isFirstSourceFinished = true;
return this.next();
}
return hasValue;
};
ConcatEnumerable.prototype.value = function () {
if (!this.currentValue.isValid()) {
this.currentValue.value = !this._isFirstSourceFinished
? this.source.value()
: this._otherSource.value();
}
return this.currentValue.value;
};
return ConcatEnumerable;
}(Enumerable));
exports.ConcatEnumerable = ConcatEnumerable;
// endregion
// region UniqueEnumerable
var UniqueEnumerable = /** @class */ (function (_super) {
__extends(UniqueEnumerable, _super);
function UniqueEnumerable(source, keySelector) {
var _this = _super.call(this, source) || this;
_this._keySelector = keySelector;
_this._seen = { primitive: { number: {}, string: {}, boolean: {} }, complex: [] };
return _this;
}
UniqueEnumerable.prototype.copy = function () {
return new UniqueEnumerable(this.source.copy(), this._keySelector);
};
UniqueEnumerable.prototype.reset = function () {
_super.prototype.reset.call(this);
this._seen = { primitive: { number: {}, string: {}, boolean: {} }, complex: [] };
};
UniqueEnumerable.prototype.isUnique = function (element) {
var key = this._keySelector !== undefined
? this._keySelector(element)
: element;
var type = typeof key;
return (type in this._seen.primitive)
? this._seen.primitive[type].hasOwnProperty(key)
? false
: this._seen.primitive[type][key] = true
: this._seen.complex.indexOf(key) !== -1
? false
: this._seen.complex.push(key) > -1;
};
UniqueEnumerable.prototype.next = function () {
var hasValue;
do {
hasValue = _super.prototype.next.call(this);
} while (hasValue && !this.isUnique(this.value()));
return hasValue;
};
return UniqueEnumerable;
}(Enumerable));
exports.UniqueEnumerable = UniqueEnumerable;
// endregion
// region RangeEnumerable
var RangeEnumerable = /** @class */ (function (_super) {
__extends(RangeEnumerable, _super);
function RangeEnumerable(source, start, count) {
var _this = this;
if ((start !== undefined && start < 0) || (count !== undefined && count < 0)) {
throw new Error("Incorrect parameters");
}
_this = _super.call(this, source) || this;
_this._start = start;
_this._count = count;
_this._currentIndex = -1;
return _this;
}
RangeEnumerable.prototype.copy = function () {
return new RangeEnumerable(this.source.copy(), this._start, this._count);
};
RangeEnumerable.prototype.reset = function () {
_super.prototype.reset.call(this);
this._currentIndex = -1;
};
RangeEnumerable.prototype.isValidIndex = function () {
var start = this._start !== undefined ? this._start : 0;
var end = this._count !== undefined ? start + this._count : undefined;
return this._currentIndex >= start && (end === undefined || this._currentIndex < end);
};
RangeEnumerable.prototype.performSkip = function () {
var start = this._start !== undefined ? this._start : 0;
var hasValue = true;
while (hasValue && this._currentIndex + 1 < start) {
hasValue = _super.prototype.next.call(this);
++this._currentIndex;
}
return hasValue;
};
RangeEnumerable.prototype.next = function () {
if (this._currentIndex < 0 && !this.performSkip()) {
return false;
}
++this._currentIndex;
return _super.prototype.next.call(this) && this.isValidIndex();
};
RangeEnumerable.prototype.value = function () {
if (!this.isValidIndex()) {
throw new Error("Out of bounds");
}
return _super.prototype.value.call(this);
};
return RangeEnumerable;
}(Enumerable));
exports.RangeEnumerable = RangeEnumerable;
// endregion
// region TransformEnumerable
var TransformEnumerable = /** @class */ (function (_super) {
__extends(TransformEnumerable, _super);
function TransformEnumerable(source, transform) {
var _this = _super.call(this, source) || this;
_this._transform = transform;
_this._currentValue = new Utils_1.Cached();
return _this;
}
TransformEnumerable.prototype.copy = function () {
return new TransformEnumerable(this.source.copy(), this._transform);
};
TransformEnumerable.prototype.value = function () {
if (!this._currentValue.isValid()) {
this._currentValue.value = this._transform(this.source.value());
}
return this._currentValue.value;
};
TransformEnumerable.prototype.reset = function () {
_super.prototype.reset.call(this);
this._currentValue.invalidate();
};
TransformEnumerable.prototype.next = function () {
this._currentValue.invalidate();
return _super.prototype.next.call(this);
};
return TransformEnumerable;
}(EnumerableBase));
exports.TransformEnumerable = TransformEnumerable;
// endregion
// region ReverseEnumerable
var ReverseEnumerable = /** @class */ (function (_super) {
__extends(ReverseEnumerable, _super);
function ReverseEnumerable(source) {
var _this = _super.call(this, source) || this;
_this._elements = new Utils_1.Cached();
_this._currentIndex = -1;
return _this;
}
ReverseEnumerable.prototype.copy = function () {
return new ReverseEnumerable(this.source.copy());
};
ReverseEnumerable.prototype.reset = function () {
this._elements.invalidate();
this._currentIndex = -1;
};
ReverseEnumerable.prototype.isValidIndex = function () {
return this._currentIndex >= 0
&& this._currentIndex < this._elements.value.length;
};
ReverseEnumerable.prototype.all = function (predicate) {
return this.source.all(predicate);
};
ReverseEnumerable.prototype.any = function (predicate) {
if (predicate !== undefined) {
return this.source.any(predicate);
}
return this.source.any();
};
ReverseEnumerable.prototype.average = function (selector) {
return this.source.average(selector);
};
ReverseEnumerable.prototype.count = function (predicate) {
if (predicate !== undefined) {
return this.source.count(predicate);
}
return this.source.count();
};
ReverseEnumerable.prototype.max = function (selector) {
if (selector !== undefined) {
return this.source.max(selector);
}
return this.source.max();
};
ReverseEnumerable.prototype.min = function (selector) {
if (selector !== undefined) {
return this.source.min(selector);
}
return this.source.min();
};
ReverseEnumerable.prototype.reverse = function () {
return this.source.copy(); // haha so smart
};
ReverseEnumerable.prototype.sum = function (selector) {
return this.source.sum(selector);
};
ReverseEnumerable.prototype.next = function () {
if (!this._elements.isValid()) {
this._elements.value = this.source.toArray();
}
++this._currentIndex;
return this.isValidIndex();
};
ReverseEnumerable.prototype.value = function () {
if (!this._elements.isValid() || !this.isValidIndex()) {
throw new Error("Out of bounds");
}
return this._elements.value[(this._elements.value.length - 1) - this._currentIndex];
};
return ReverseEnumerable;
}(Enumerable));
exports.ReverseEnumerable = ReverseEnumerable;
// endregion
// region OrderedEnumerable
var OrderedEnumerable = /** @class */ (function (_super) {
__extends(OrderedEnumerable, _super);
function OrderedEnumerable(source, comparer) {
var _this = _super.call(this, source) || this;
_this._comparer = comparer;
_this._elements = new Utils_1.Cached();
_this._currentIndex = -1;
return _this;
}
OrderedEnumerable.prototype.isValidIndex = function () {
return this._currentIndex >= 0
&& this._currentIndex < this._elements.value.length;
};
OrderedEnumerable.prototype.orderBy = function (keySelector, comparer) {
return new OrderedEnumerable(this.source.copy(), Comparers_1.createComparer(keySelector, true, comparer));
};
OrderedEnumerable.prototype.orderByDescending = function (keySelector) {
return new OrderedEnumerable(this.source.copy(), Comparers_1.createComparer(keySelector, false, undefined));
};
OrderedEnumerable.prototype.thenBy = function (keySelector, comparer) {
return new OrderedEnumerable(this.source.copy(), Comparers_1.combineComparers(this._comparer, Comparers_1.createComparer(keySelector, true, comparer)));
};
OrderedEnumerable.prototype.thenByDescending = function (keySelector) {
return new OrderedEnumerable(this.source.copy(), Comparers_1.combineComparers(this._comparer, Comparers_1.createComparer(keySelector, false, undefined)));
};
OrderedEnumerable.prototype.reset = function () {
this._elements.invalidate();
this._currentIndex = -1;
};
OrderedEnumerable.prototype.copy = function () {
return new OrderedEnumerable(this.source.copy(), this._comparer);
};
OrderedEnumerable.prototype.value = function () {
if (!this._elements.isValid() || !this.isValidIndex()) {
throw new Error("Out of bounds");
}
return this._elements.value[this._currentIndex];
};
OrderedEnumerable.prototype.next = function () {
if (!this._elements.isValid()) {
this._elements.value = this.toArray();
}
++this._currentIndex;
return this.isValidIndex();
};
OrderedEnumerable.prototype.toArray = function () {
// Allocate the array before sorting
// It's faster than working with anonymous reference
var result = this.source.toArray();
return result.sort(this._comparer);
};
return OrderedEnumerable;
}(EnumerableBase));
exports.OrderedEnumerable = OrderedEnumerable;
// endregion
// region ArrayEnumerable
var ArrayEnumerable = /** @class */ (function (_super) {
__extends(ArrayEnumerable, _super);
function ArrayEnumerable(source) {
var _this = _super.call(this, new Iterators_1.ArrayIterator(source)) || this;
_this.list = new Collections_1.List(source);
return _this;
}
ArrayEnumerable.prototype.toArray = function () {
return this.list.toArray();
};
ArrayEnumerable.prototype.aggregate = function (aggregator, initialValue) {
if (initialValue !== undefined) {
return this.list.aggregate(aggregator, initialValue);
}
return this.list.aggregate(aggregator);
};
ArrayEnumerable.prototype.any = function (predicate) {
if (predicate !== undefined) {
return this.list.any(predicate);
}
return this.list.any();
};
ArrayEnumerable.prototype.all = function (predicate) {
return this.list.all(predicate);
};
ArrayEnumerable.prototype.average = function (selector) {
return this.list.average(selector);
};
ArrayEnumerable.prototype.count = function (predicate) {
if (predicate !== undefined) {
return this.list.count(predicate);
}
return this.list.count();
};
ArrayEnumerable.prototype.copy = function () {
return new ArrayEnumerable(this.list.asArray());
};
ArrayEnumerable.prototype.elementAtOrDefault = function (index) {
return this.list.elementAtOrDefault(index);
};
ArrayEnumerable.prototype.firstOrDefault = function (predicate) {
if (predicate !== undefined) {
return this.list.firstOrDefault(predicate);
}
return this.list.firstOrDefault();
};
ArrayEnumerable.prototype.lastOrDefault = function (predicate) {
if (predicate !== undefined) {
return this.list.lastOrDefault(predicate);
}
return this.list.lastOrDefault();
};
return ArrayEnumerable;
}(Enumerable));
exports.ArrayEnumerable = ArrayEnumerable;
// endregion
//# sourceMappingURL=Enumerables.js.map