@adamburgess/linq
Version:
A linq library.
279 lines (278 loc) • 7.33 kB
JavaScript
import { byMin_byMax_min_max, concat, createLazyGenerator, distinct, flat, groupBy, groupByMap, map, reverse, skip, skipWhile, take, takeWhile, where } from "./enumerable.js";
class SequenceKlass {
constructor(it) {
this.it = it;
}
map(f) {
return new SequenceKlass(map(this, f));
}
where(f) {
return new SequenceKlass(where(this, f));
}
reverse() {
return new SequenceKlass(reverse(this));
}
groupBy(keySelector, elementSelector) {
return new SequenceKlass(groupBy(this, keySelector, elementSelector)).map((kv) => new KeySequenceKlass(kv[1], kv[0]));
}
orderBy(selector, comparer) {
return new OrderedSequenceKlass(this, [{
selector,
comparer: comparer || defaultComparer,
ascending: true
}]);
}
orderByDescending(selector, comparer) {
return new OrderedSequenceKlass(this, [{
selector,
comparer: comparer || defaultComparer,
ascending: false
}]);
}
take(count) {
return new SequenceKlass(take(this, count));
}
takeWhile(predicate) {
return new SequenceKlass(takeWhile(this, predicate));
}
skip(count) {
return new SequenceKlass(skip(this, count));
}
skipWhile(predicate) {
return new SequenceKlass(skipWhile(this, predicate));
}
append(iterable) {
return new SequenceKlass(concat(this, iterable));
}
prepend(iterable) {
return new SequenceKlass(concat(iterable, this));
}
distinct(keySelector) {
return new SequenceKlass(distinct(this, keySelector));
}
flat(projector) {
return new SequenceKlass(flat(projector ? this.map(projector) : this));
}
join(innerSequence, outerKeySelector, innerKeySelector, resultSelector) {
const distinctInner = from(innerSequence).toMap(innerKeySelector, (x) => x);
const that = this;
return new SequenceKlass(createLazyGenerator(function* join() {
for (const outerValue of that) {
const key = outerKeySelector(outerValue);
const innerValue = distinctInner.get(key);
if (innerValue) {
yield resultSelector(outerValue, innerValue);
}
}
}));
}
groupJoin(innerSequence, outerKeySelector, innerKeySelector, resultSelector) {
const that = this;
return new SequenceKlass(createLazyGenerator(function* groupJoin() {
const groupedInner = groupByMap(innerSequence, innerKeySelector);
for (const outerValue of that) {
const key = outerKeySelector(outerValue);
const innerValue = groupedInner.get(key);
if (innerValue) {
yield resultSelector(outerValue, from(innerValue));
}
}
}));
}
count() {
let count = 0;
for (const _ of this)
count++;
return count;
}
sum(f) {
let value = 0;
for (const x of this) {
value += f ? f(x) : x;
}
return value;
}
average(f) {
let value = 0;
let count = 0;
for (const x of this) {
value += f ? f(x) : x;
count++;
}
if (count === 0)
throw new Error("empty");
return value / count;
}
min(f) {
return byMin_byMax_min_max(this, f, true, false);
}
max(f) {
return byMin_byMax_min_max(this, f, false, false);
}
minBy(f) {
return byMin_byMax_min_max(this, f, true, true);
}
maxBy(f) {
return byMin_byMax_min_max(this, f, false, true);
}
all(predicate) {
for (const x of this) {
if (!predicate(x))
return false;
}
return true;
}
any(predicate) {
for (const x of this) {
if (predicate ? predicate(x) : true)
return true;
}
return false;
}
none(predicate) {
return !this.any(predicate);
}
contains(value) {
return this.any((x) => x === value);
}
toArray() {
return Array.from(this);
}
toMap(keySelector, elementSelector) {
const map2 = /* @__PURE__ */ new Map();
for (const e of this) {
const key = keySelector(e);
if (!map2.has(key))
map2.set(key, elementSelector(e));
}
return map2;
}
toObject(keySelector, elementSelector) {
const record = {};
const keys = /* @__PURE__ */ new Set();
for (const x of this) {
const key = keySelector(x);
if (!keys.has(key)) {
record[key] = elementSelector(x);
keys.add(key);
}
}
return record;
}
toSet(projector) {
return projector ? new Set(this.map(projector)) : new Set(this);
}
first(predicate) {
if (predicate)
return this.where(predicate).first();
const iterator = this[Symbol.iterator]();
const result = iterator.next();
if (result.done)
throw new Error("empty");
return result.value;
}
firstOrDefault(predicate) {
if (predicate)
return this.where(predicate).firstOrDefault();
const iterator = this[Symbol.iterator]();
const result = iterator.next();
return result.value;
}
single(predicate) {
if (predicate)
return this.where(predicate).single();
const iterator = this[Symbol.iterator]();
const result1 = iterator.next();
if (result1.done)
throw new Error("empty");
const result2 = iterator.next();
if (!result2.done)
throw new Error("more than 1");
return result1.value;
}
singleOrDefault(predicate) {
if (predicate)
return this.where(predicate).singleOrDefault();
const iterator = this[Symbol.iterator]();
const result1 = iterator.next();
if (result1.done)
return void 0;
const result2 = iterator.next();
if (!result2.done)
return void 0;
return result1.value;
}
last(predicate) {
if (predicate)
return this.where(predicate).last();
let stored = void 0;
for (const x of this) {
stored = x;
}
if (stored === void 0)
throw new Error("empty");
return stored;
}
lastOrDefault(predicate) {
if (predicate)
return this.where(predicate).lastOrDefault();
let stored = void 0;
for (const x of this) {
stored = x;
}
return stored;
}
joinString(separator) {
return this.toArray().join(separator);
}
[Symbol.iterator]() {
return this.it[Symbol.iterator]();
}
}
class KeySequenceKlass extends SequenceKlass {
constructor(it, key) {
super(it);
this.key = key;
}
}
const defaultComparer = (a, b) => a > b ? 1 : a < b ? -1 : 0;
class OrderedSequenceKlass extends SequenceKlass {
constructor(it, sc) {
super(it);
this.sc = sc;
}
thenBy(selector, comparer) {
return new OrderedSequenceKlass(this.it, [...this.sc, {
selector,
comparer: comparer || defaultComparer,
ascending: true
}]);
}
thenByDescending(selector, comparer) {
return new OrderedSequenceKlass(this.it, [...this.sc, {
selector,
comparer: comparer || defaultComparer,
ascending: false
}]);
}
[Symbol.iterator]() {
const elements = Array.from(this.it);
elements.sort((a, b) => {
for (const compare of this.sc) {
let result = compare.comparer(compare.selector(a), compare.selector(b));
if (!compare.ascending)
result = -result;
if (result !== 0)
return result;
}
return 0;
});
return elements[Symbol.iterator]();
}
}
export function from(it) {
if (it instanceof SequenceKlass)
return it;
return new SequenceKlass(it);
}
export default from;