2026-04-12 16:38:59 +02:00

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;
});
}