140 lines
3.4 KiB
JavaScript
140 lines
3.4 KiB
JavaScript
// LINQ-like Enumerable class wrapping lazy generator chains
|
|
|
|
class Enumerable {
|
|
constructor(iteratorFn) {
|
|
this._iteratorFn = iteratorFn;
|
|
}
|
|
|
|
[Symbol.iterator]() {
|
|
return this._iteratorFn();
|
|
}
|
|
|
|
_chain(generatorFn) {
|
|
const source = this;
|
|
return new Enumerable(function* () {
|
|
yield* generatorFn(source);
|
|
});
|
|
}
|
|
|
|
where(predicate) {
|
|
return this._chain(function* (source) {
|
|
for (const item of source)
|
|
if (predicate(item))
|
|
yield item;
|
|
});
|
|
}
|
|
|
|
select(selector) {
|
|
return this._chain(function* (source) {
|
|
for (const item of source)
|
|
yield selector(item);
|
|
});
|
|
}
|
|
|
|
take(count) {
|
|
count = Math.max(0, count);
|
|
return this._chain(function* (source) {
|
|
for (const item of source) {
|
|
if (count-- <= 0) break;
|
|
yield item;
|
|
}
|
|
});
|
|
}
|
|
|
|
skip(count) {
|
|
count = Math.max(0, count);
|
|
return this._chain(function* (source) {
|
|
for (const item of source) {
|
|
if (count-- > 0) continue;
|
|
yield item;
|
|
}
|
|
});
|
|
}
|
|
|
|
isLast() {
|
|
return this._chain(function* (source) {
|
|
const iter = source[Symbol.iterator]();
|
|
let current = iter.next();
|
|
let index = 0;
|
|
while (!current.done) {
|
|
const next = iter.next();
|
|
yield [current.value, next.done, index];
|
|
current = next;
|
|
index++;
|
|
}
|
|
});
|
|
}
|
|
|
|
forEach(action) {
|
|
for (const item of this) {
|
|
if (Array.isArray(item)) {
|
|
action(...item);
|
|
} else {
|
|
action(item);
|
|
}
|
|
}
|
|
}
|
|
|
|
toArray() {
|
|
return Array.from(this);
|
|
}
|
|
|
|
firstOrDefault(predicate) {
|
|
const source = predicate ? this.where(predicate) : this;
|
|
for (const item of source) return item;
|
|
return undefined;
|
|
}
|
|
|
|
first(predicate) {
|
|
const source = predicate ? this.where(predicate) : this;
|
|
for (const item of source) return item;
|
|
throw new Error("No elements in sequence.");
|
|
}
|
|
|
|
lastOrDefault(predicate) {
|
|
const source = predicate ? this.where(predicate) : this;
|
|
let lastValue = undefined;
|
|
for (const item of source) lastValue = item;
|
|
return lastValue;
|
|
}
|
|
|
|
last(predicate) {
|
|
const source = predicate ? this.where(predicate) : this;
|
|
let lastValue = undefined;
|
|
let found = false;
|
|
for (const item of source) {
|
|
lastValue = item;
|
|
found = true;
|
|
}
|
|
if (!found) throw new Error("No elements in sequence.");
|
|
return lastValue;
|
|
}
|
|
|
|
any(predicate) {
|
|
const source = predicate ? this.where(predicate) : this;
|
|
for (const _ of source) return true;
|
|
return false;
|
|
}
|
|
|
|
all(predicate) {
|
|
for (const item of this)
|
|
if (!predicate(item))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
count(predicate) {
|
|
let count = 0;
|
|
const source = predicate ? this.where(predicate) : this;
|
|
for (const _ of source) count++;
|
|
return count;
|
|
}
|
|
}
|
|
|
|
Array.prototype.asEnumerable = function () {
|
|
const arr = this;
|
|
return new Enumerable(function* () {
|
|
for (const item of arr)
|
|
yield item;
|
|
});
|
|
} |