DRAFT: implement sequence
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
export {sequence} from "./sequence.js";
|
||||||
|
|||||||
437
src/sequence.ts
Normal file
437
src/sequence.ts
Normal file
@@ -0,0 +1,437 @@
|
|||||||
|
import {map} from "./sequence/map.js";
|
||||||
|
import {collect} from "./sequence/collect.js";
|
||||||
|
import {forEach} from "./sequence/forEach.js";
|
||||||
|
import {filter} from "./sequence/filter.js";
|
||||||
|
import {count} from "./sequence/count.js";
|
||||||
|
import {isEmpty} from "./sequence/isEmpty.js";
|
||||||
|
import {isNotEmpty} from "./sequence/isNotEmpty.js";
|
||||||
|
import {indices} from "./sequence/indices.js";
|
||||||
|
import {withIndex} from "./sequence/withIndex.js";
|
||||||
|
import {filterIndexed} from "./sequence/filterIndexed.js";
|
||||||
|
import {mapIndexed} from "./sequence/mapIndexed.js";
|
||||||
|
import {any} from "./sequence/any.js";
|
||||||
|
import {none} from "./sequence/none.js";
|
||||||
|
import {all} from "./sequence/all.js";
|
||||||
|
import {first} from "./sequence/first.js";
|
||||||
|
import {firstOrNull} from "./sequence/firstOrNull.js";
|
||||||
|
import {last} from "./sequence/last.js";
|
||||||
|
import {lastOrNull} from "./sequence/lastOrNull.js";
|
||||||
|
import {single} from "./sequence/single.js";
|
||||||
|
import {singleOrNull} from "./sequence/singleOrNull.js";
|
||||||
|
import {plus} from "./sequence/plus.js";
|
||||||
|
import {distinct} from "./sequence/distinct.js";
|
||||||
|
import {distinctBy} from "./sequence/distinctBy.js";
|
||||||
|
import {drop} from "./sequence/drop.js";
|
||||||
|
import {take} from "./sequence/take.js";
|
||||||
|
import {slice} from "./sequence/slice.js";
|
||||||
|
import {dropWhile} from "./sequence/dropWhile.js";
|
||||||
|
import {dropUntil} from "./sequence/dropUntil.js";
|
||||||
|
import {takeWhile} from "./sequence/takeWhile.js";
|
||||||
|
import {takeUntil} from "./sequence/takeUntil.js";
|
||||||
|
import {flatMap} from "./sequence/flatMap.js";
|
||||||
|
import {flatMapIndexed} from "./sequence/flatMapIndexed.js";
|
||||||
|
import {associate} from "./sequence/associate.js";
|
||||||
|
import {associateBy} from "./sequence/associateBy.js";
|
||||||
|
import {associateWith} from "./sequence/associateWith.js";
|
||||||
|
import {get} from "./sequence/get.js";
|
||||||
|
import {getOrNull} from "./sequence/getOrNull.js";
|
||||||
|
import {sumBy} from "./sequence/sumBy.js";
|
||||||
|
import {averageBy} from "./sequence/averageBy.js";
|
||||||
|
import {contains} from "./sequence/contains.js";
|
||||||
|
import {containsAll} from "./sequence/containsAll.js";
|
||||||
|
import {minBy} from "./sequence/minBy.js";
|
||||||
|
import {minByOrNull} from "./sequence/minByOrNull.js";
|
||||||
|
import {maxBy} from "./sequence/maxBy.js";
|
||||||
|
import {maxByOrNull} from "./sequence/maxByOrNull.js";
|
||||||
|
import {minOf} from "./sequence/minOf.js";
|
||||||
|
import {minOfOrNull} from "./sequence/minOfOrNull.js";
|
||||||
|
import {maxOf} from "./sequence/maxOf.js";
|
||||||
|
import {maxOfOrNull} from "./sequence/maxOfOrNull.js";
|
||||||
|
import {minWith} from "./sequence/minWith.js";
|
||||||
|
import {minWithOrNull} from "./sequence/minWithOrNull.js";
|
||||||
|
import {maxWith} from "./sequence/maxWith.js";
|
||||||
|
import {maxWithOrNull} from "./sequence/maxWithOrNull.js";
|
||||||
|
import {minus} from "./sequence/minus.js";
|
||||||
|
import {reduce} from "./sequence/reduce.js";
|
||||||
|
import {reduceOrNull} from "./sequence/reduceOrNull.js";
|
||||||
|
import {fold} from "./sequence/fold.js";
|
||||||
|
import {scan} from "./sequence/scan.js";
|
||||||
|
import {partition} from "./sequence/partition.js";
|
||||||
|
import {firstIndex} from "./sequence/firstIndex.js";
|
||||||
|
import {firstIndexOrNull} from "./sequence/firstIndexOrNull.js";
|
||||||
|
import {lastIndex} from "./sequence/lastIndex.js";
|
||||||
|
import {lastIndexOrNull} from "./sequence/lastIndexOrNull.js";
|
||||||
|
import {sortedWith} from "./sequence/sortedWith.js";
|
||||||
|
import {sortedBy} from "./sequence/sortedBy.js";
|
||||||
|
import {reversed} from "./sequence/reversed.js";
|
||||||
|
import {windowed} from "./sequence/windowed.js";
|
||||||
|
import {chunked} from "./sequence/chunked.js";
|
||||||
|
import {zip} from "./sequence/zip.js";
|
||||||
|
import {unzip} from "./sequence/unzip.js";
|
||||||
|
import {sum} from "./sequence/sum.js";
|
||||||
|
import {average} from "./sequence/average.js";
|
||||||
|
import {min} from "./sequence/min.js";
|
||||||
|
import {minOrNull} from "./sequence/minOrNull.js";
|
||||||
|
import {max} from "./sequence/max.js";
|
||||||
|
import {maxOrNull} from "./sequence/maxOrNull.js";
|
||||||
|
import {flatten} from "./sequence/flatten.js";
|
||||||
|
import {sorted} from "./sequence/sorted.js";
|
||||||
|
import {onEach} from "./sequence/onEach.js";
|
||||||
|
import {joinToString} from "./sequence/joinToString.js";
|
||||||
|
import {groupBy} from "./sequence/groupBy.js";
|
||||||
|
|
||||||
|
export type Sequence<T> = {
|
||||||
|
[Symbol.iterator](): Iterator<T>
|
||||||
|
collect(): T[]
|
||||||
|
|
||||||
|
onEach(action: (it: T) => void): void
|
||||||
|
forEach(action: (it: T) => void): void
|
||||||
|
|
||||||
|
isEmpty(): boolean
|
||||||
|
isNotEmpty(): boolean
|
||||||
|
count(predicate?: (it: T) => boolean): number
|
||||||
|
|
||||||
|
firstIndex(predicate?: (it: T) => boolean): number
|
||||||
|
firstIndexOrNull(predicate?: (it: T) => boolean): number | null
|
||||||
|
lastIndex(predicate?: (it: T) => boolean): number
|
||||||
|
lastIndexOrNull(predicate?: (it: T) => boolean): number | null
|
||||||
|
indices(): Sequence<number>
|
||||||
|
withIndex(): Sequence<[number, T]>
|
||||||
|
|
||||||
|
contains(item: T): boolean
|
||||||
|
containsAll(items: Iterable<T>): boolean
|
||||||
|
any(predicate: (it: T) => boolean): boolean
|
||||||
|
all(predicate: (it: T) => boolean): boolean
|
||||||
|
none(predicate: (it: T) => boolean): boolean
|
||||||
|
|
||||||
|
get(index: number): T
|
||||||
|
getOrNull(index: number): T | null
|
||||||
|
first(predicate?: (it: T) => boolean): T
|
||||||
|
firstOrNull(predicate?: (it: T) => boolean): T | null
|
||||||
|
last(predicate?: (it: T) => boolean): T
|
||||||
|
lastOrNull(predicate?: (it: T) => boolean): T | null
|
||||||
|
single(predicate?: (it: T) => boolean): T
|
||||||
|
singleOrNull(predicate?: (it: T) => boolean): T | null
|
||||||
|
|
||||||
|
min(this: Sequence<number>): number
|
||||||
|
minOrNull(this: Sequence<number>): number | null
|
||||||
|
minWith(compare: (a: T, b: T) => number): T
|
||||||
|
minWithOrNull(compare: (a: T, b: T) => number): T | null
|
||||||
|
minBy(transform: (it: T) => number): T
|
||||||
|
minByOrNull(transform: (it: T) => number): T | null
|
||||||
|
minOf(transform: (it: T) => number): number
|
||||||
|
minOfOrNull(transform: (it: T) => number): number | null
|
||||||
|
max(this: Sequence<number>): number
|
||||||
|
maxOrNull(this: Sequence<number>): number | null
|
||||||
|
maxWith(compare: (a: T, b: T) => number): T
|
||||||
|
maxWithOrNull(compare: (a: T, b: T) => number): T | null
|
||||||
|
maxBy(transform: (it: T) => number): T
|
||||||
|
maxByOrNull(transform: (it: T) => number): T | null
|
||||||
|
maxOf(transform: (it: T) => number): number
|
||||||
|
maxOfOrNull(transform: (it: T) => number): number | null
|
||||||
|
|
||||||
|
reduce(accumulate: (acc: T, it: T) => T): T
|
||||||
|
reduceOrNull(accumulate: (acc: T, it: T) => T): T | null
|
||||||
|
fold<R>(initial: R, accumulate: (acc: R, it: T) => R): R
|
||||||
|
scan<R>(initial: R, accumulate: (acc: R, it: T) => R): Sequence<R>
|
||||||
|
sum(this: Sequence<number>): number
|
||||||
|
sumBy(transform: (it: T) => number): number
|
||||||
|
average(this: Sequence<number>): number
|
||||||
|
averageBy(transform: (it: T) => number): number
|
||||||
|
|
||||||
|
plus(items: Iterable<T>): Sequence<T>
|
||||||
|
minus(items: Iterable<T>): Sequence<T>
|
||||||
|
|
||||||
|
filter<R extends T>(predicate: (it: T) => it is R): Sequence<R>
|
||||||
|
filter(predicate: (it: T) => boolean): Sequence<T>
|
||||||
|
filterIndexed<R extends T>(predicate: (index: number, it: T) => it is R): Sequence<R>
|
||||||
|
filterIndexed(predicate: (index: number, it: T) => boolean): Sequence<T>
|
||||||
|
partition(predicate: (it: T) => boolean): [T[], T[]]
|
||||||
|
drop(count: number): Sequence<T>
|
||||||
|
dropWhile(predicate: (it: T) => boolean): Sequence<T>
|
||||||
|
dropUntil(predicate: (it: T) => boolean): Sequence<T>
|
||||||
|
take(count: number): Sequence<T>
|
||||||
|
takeWhile(predicate: (it: T) => boolean): Sequence<T>
|
||||||
|
takeUntil(predicate: (it: T) => boolean): Sequence<T>
|
||||||
|
slice(start: number, end?: number): Sequence<T>
|
||||||
|
distinct(): Sequence<T>
|
||||||
|
distinctBy<K>(transform: (it: T) => K): Sequence<T>
|
||||||
|
|
||||||
|
map<R>(transform: (it: T) => R): Sequence<R>
|
||||||
|
mapIndexed<R>(transform: (index: number, it: T) => R): Sequence<R>
|
||||||
|
flatten<R>(this: Sequence<Iterable<R>>): Sequence<R>
|
||||||
|
flatMap<R>(transform: (it: T) => Iterable<R>): Sequence<R>
|
||||||
|
flatMapIndexed<R>(transform: (index: number, it: T) => Iterable<R>): Sequence<R>
|
||||||
|
associate<K, V>(transform: (it: T) => [K, V]): Sequence<[K, V]>
|
||||||
|
associateBy<K>(transform: (it: T) => K): Sequence<[K, T]>
|
||||||
|
associateWith<V>(transform: (it: T) => V): Sequence<[T, V]>
|
||||||
|
zip<B>(items: Iterable<B>): Sequence<[T, B]>
|
||||||
|
unzip<A, B>(this: Sequence<[A, B]>): [A[], B[]]
|
||||||
|
|
||||||
|
windowed(size: number, step?: number, partial?: boolean): Sequence<T[]>
|
||||||
|
chunked(size: number): Sequence<T[]>
|
||||||
|
|
||||||
|
groupBy<K>(transform: (it: T) => K): [K, T[]][]
|
||||||
|
|
||||||
|
reversed(): T[]
|
||||||
|
sorted(this: Sequence<number>): number[]
|
||||||
|
sortedWith(compare: (a: T, b: T) => number): T[]
|
||||||
|
sortedBy(transform: (it: T) => number): T[]
|
||||||
|
|
||||||
|
joinToString(separator: string, transform?: (it: T) => string): string
|
||||||
|
}
|
||||||
|
|
||||||
|
export function sequence<T>(value: Iterable<T>): Sequence<T> {
|
||||||
|
return wrap(() => value);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function wrap<T>(factory: () => Iterable<T>): Sequence<T> {
|
||||||
|
return {
|
||||||
|
[Symbol.iterator]() {
|
||||||
|
return factory()[Symbol.iterator]();
|
||||||
|
},
|
||||||
|
collect() {
|
||||||
|
return collect(factory());
|
||||||
|
},
|
||||||
|
onEach(action) {
|
||||||
|
return wrap(() => onEach(factory(), action));
|
||||||
|
},
|
||||||
|
forEach(action) {
|
||||||
|
forEach(factory(), action);
|
||||||
|
},
|
||||||
|
isEmpty() {
|
||||||
|
return isEmpty(factory());
|
||||||
|
},
|
||||||
|
isNotEmpty() {
|
||||||
|
return isNotEmpty(factory());
|
||||||
|
},
|
||||||
|
count(predicate) {
|
||||||
|
return count(factory(), predicate);
|
||||||
|
},
|
||||||
|
firstIndex(predicate) {
|
||||||
|
return firstIndex(factory(), predicate);
|
||||||
|
},
|
||||||
|
firstIndexOrNull(predicate) {
|
||||||
|
return firstIndexOrNull(factory(), predicate);
|
||||||
|
},
|
||||||
|
lastIndex(predicate) {
|
||||||
|
return lastIndex(factory(), predicate);
|
||||||
|
},
|
||||||
|
lastIndexOrNull(predicate) {
|
||||||
|
return lastIndexOrNull(factory(), predicate);
|
||||||
|
},
|
||||||
|
indices() {
|
||||||
|
return wrap(() => indices(factory()));
|
||||||
|
},
|
||||||
|
withIndex() {
|
||||||
|
return wrap(() => withIndex(factory()));
|
||||||
|
},
|
||||||
|
contains(item) {
|
||||||
|
return contains(factory(), item);
|
||||||
|
},
|
||||||
|
containsAll(items) {
|
||||||
|
return containsAll(factory(), items);
|
||||||
|
},
|
||||||
|
any(predicate) {
|
||||||
|
return any(factory(), predicate);
|
||||||
|
},
|
||||||
|
all(predicate) {
|
||||||
|
return all(factory(), predicate);
|
||||||
|
},
|
||||||
|
none(predicate) {
|
||||||
|
return none(factory(), predicate);
|
||||||
|
},
|
||||||
|
get(index) {
|
||||||
|
return get(factory(), index);
|
||||||
|
},
|
||||||
|
getOrNull(index) {
|
||||||
|
return getOrNull(factory(), index);
|
||||||
|
},
|
||||||
|
first(predicate) {
|
||||||
|
return first(factory(), predicate);
|
||||||
|
},
|
||||||
|
firstOrNull(predicate) {
|
||||||
|
return firstOrNull(factory(), predicate);
|
||||||
|
},
|
||||||
|
last(predicate) {
|
||||||
|
return last(factory(), predicate);
|
||||||
|
},
|
||||||
|
lastOrNull(predicate) {
|
||||||
|
return lastOrNull(factory(), predicate);
|
||||||
|
},
|
||||||
|
single(predicate) {
|
||||||
|
return single(factory(), predicate);
|
||||||
|
},
|
||||||
|
singleOrNull(predicate) {
|
||||||
|
return singleOrNull(factory(), predicate);
|
||||||
|
},
|
||||||
|
min() {
|
||||||
|
return min(factory() as any);
|
||||||
|
},
|
||||||
|
minOrNull() {
|
||||||
|
return minOrNull(factory() as any);
|
||||||
|
},
|
||||||
|
minWith(compare) {
|
||||||
|
return minWith(factory(), compare);
|
||||||
|
},
|
||||||
|
minWithOrNull(compare) {
|
||||||
|
return minWithOrNull(factory(), compare);
|
||||||
|
},
|
||||||
|
minBy(transform) {
|
||||||
|
return minBy(factory(), transform);
|
||||||
|
},
|
||||||
|
minByOrNull(transform) {
|
||||||
|
return minByOrNull(factory(), transform);
|
||||||
|
},
|
||||||
|
minOf(transform) {
|
||||||
|
return minOf(factory(), transform);
|
||||||
|
},
|
||||||
|
minOfOrNull(transform) {
|
||||||
|
return minOfOrNull(factory(), transform);
|
||||||
|
},
|
||||||
|
max() {
|
||||||
|
return max(factory() as any);
|
||||||
|
},
|
||||||
|
maxOrNull() {
|
||||||
|
return maxOrNull(factory() as any);
|
||||||
|
},
|
||||||
|
maxWith(compare) {
|
||||||
|
return maxWith(factory(), compare);
|
||||||
|
},
|
||||||
|
maxWithOrNull(compare) {
|
||||||
|
return maxWithOrNull(factory(), compare);
|
||||||
|
},
|
||||||
|
maxBy(transform) {
|
||||||
|
return maxBy(factory(), transform);
|
||||||
|
},
|
||||||
|
maxByOrNull(transform) {
|
||||||
|
return maxByOrNull(factory(), transform);
|
||||||
|
},
|
||||||
|
maxOf(transform) {
|
||||||
|
return maxOf(factory(), transform);
|
||||||
|
},
|
||||||
|
maxOfOrNull(transform) {
|
||||||
|
return maxOfOrNull(factory(), transform);
|
||||||
|
},
|
||||||
|
reduce(accumulate) {
|
||||||
|
return reduce(factory(), accumulate);
|
||||||
|
},
|
||||||
|
reduceOrNull(accumulate) {
|
||||||
|
return reduceOrNull(factory(), accumulate);
|
||||||
|
},
|
||||||
|
fold(initial, accumulate) {
|
||||||
|
return fold(factory(), initial, accumulate);
|
||||||
|
},
|
||||||
|
scan(initial, accumulate) {
|
||||||
|
return wrap(() => scan(factory(), initial, accumulate));
|
||||||
|
},
|
||||||
|
sum() {
|
||||||
|
return sum(factory() as any);
|
||||||
|
},
|
||||||
|
sumBy(transform) {
|
||||||
|
return sumBy(factory(), transform);
|
||||||
|
},
|
||||||
|
average() {
|
||||||
|
return average(factory() as any);
|
||||||
|
},
|
||||||
|
averageBy(transform) {
|
||||||
|
return averageBy(factory(), transform);
|
||||||
|
},
|
||||||
|
plus(items) {
|
||||||
|
return wrap(() => plus(factory(), items));
|
||||||
|
},
|
||||||
|
minus(items) {
|
||||||
|
return wrap(() => minus(factory(), items));
|
||||||
|
},
|
||||||
|
filter(predicate: (it: T) => boolean) {
|
||||||
|
return wrap(() => filter(factory(), predicate));
|
||||||
|
},
|
||||||
|
filterIndexed(predicate: (index: number, it: T) => boolean) {
|
||||||
|
return wrap(() => filterIndexed(factory(), predicate));
|
||||||
|
},
|
||||||
|
partition(predicate) {
|
||||||
|
return partition(factory(), predicate);
|
||||||
|
},
|
||||||
|
drop(count) {
|
||||||
|
return wrap(() => drop(factory(), count));
|
||||||
|
},
|
||||||
|
dropWhile(predicate) {
|
||||||
|
return wrap(() => dropWhile(factory(), predicate));
|
||||||
|
},
|
||||||
|
dropUntil(predicate) {
|
||||||
|
return wrap(() => dropUntil(factory(), predicate));
|
||||||
|
},
|
||||||
|
take(count) {
|
||||||
|
return wrap(() => take(factory(), count));
|
||||||
|
},
|
||||||
|
takeWhile(predicate) {
|
||||||
|
return wrap(() => takeWhile(factory(), predicate));
|
||||||
|
},
|
||||||
|
takeUntil(predicate) {
|
||||||
|
return wrap(() => takeUntil(factory(), predicate));
|
||||||
|
},
|
||||||
|
slice(start, end) {
|
||||||
|
return wrap(() => slice(factory(), start, end));
|
||||||
|
},
|
||||||
|
distinct() {
|
||||||
|
return wrap(() => distinct(factory()));
|
||||||
|
},
|
||||||
|
distinctBy(transform) {
|
||||||
|
return wrap(() => distinctBy(factory(), transform));
|
||||||
|
},
|
||||||
|
map(transform) {
|
||||||
|
return wrap(() => map(factory(), transform));
|
||||||
|
},
|
||||||
|
mapIndexed(transform) {
|
||||||
|
return wrap(() => mapIndexed(factory(), transform));
|
||||||
|
},
|
||||||
|
flatten() {
|
||||||
|
return wrap(() => flatten(factory() as any));
|
||||||
|
},
|
||||||
|
flatMap(transform) {
|
||||||
|
return wrap(() => flatMap(factory(), transform));
|
||||||
|
},
|
||||||
|
flatMapIndexed(transform) {
|
||||||
|
return wrap(() => flatMapIndexed(factory(), transform));
|
||||||
|
},
|
||||||
|
associate(transform) {
|
||||||
|
return wrap(() => associate(factory(), transform));
|
||||||
|
},
|
||||||
|
associateBy(transform) {
|
||||||
|
return wrap(() => associateBy(factory(), transform));
|
||||||
|
},
|
||||||
|
associateWith(transform) {
|
||||||
|
return wrap(() => associateWith(factory(), transform));
|
||||||
|
},
|
||||||
|
zip(items) {
|
||||||
|
return wrap(() => zip(factory(), items));
|
||||||
|
},
|
||||||
|
unzip() {
|
||||||
|
return unzip(factory() as any);
|
||||||
|
},
|
||||||
|
windowed(size, step, partial) {
|
||||||
|
return wrap(() => windowed(factory(), size, step, partial));
|
||||||
|
},
|
||||||
|
chunked(size) {
|
||||||
|
return wrap(() => chunked(factory(), size));
|
||||||
|
},
|
||||||
|
groupBy(transform) {
|
||||||
|
return groupBy(factory(), transform);
|
||||||
|
},
|
||||||
|
reversed() {
|
||||||
|
return reversed(factory());
|
||||||
|
},
|
||||||
|
sorted() {
|
||||||
|
return sorted(factory() as any);
|
||||||
|
},
|
||||||
|
sortedWith(compare) {
|
||||||
|
return sortedWith(factory(), compare);
|
||||||
|
},
|
||||||
|
sortedBy(transform) {
|
||||||
|
return sortedBy(factory(), transform);
|
||||||
|
},
|
||||||
|
joinToString(separator, transform) {
|
||||||
|
return joinToString(factory(), separator, transform);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
6
src/sequence/all.ts
Normal file
6
src/sequence/all.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export function all<T>(value: Iterable<T>, predicate: (it: T) => boolean): boolean {
|
||||||
|
for (const it of value) {
|
||||||
|
if (!predicate(it)) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
6
src/sequence/any.ts
Normal file
6
src/sequence/any.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export function any<T>(value: Iterable<T>, predicate: (it: T) => boolean): boolean {
|
||||||
|
for (const it of value) {
|
||||||
|
if (predicate(it)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
5
src/sequence/associate.ts
Normal file
5
src/sequence/associate.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export function* associate<T, K, V>(value: Iterable<T>, transform: (it: T) => [K, V]): Iterable<[K, V]> {
|
||||||
|
for (const it of value) {
|
||||||
|
yield transform(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
5
src/sequence/associateBy.ts
Normal file
5
src/sequence/associateBy.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export function* associateBy<T, K>(value: Iterable<T>, transform: (it: T) => K): Iterable<[K, T]> {
|
||||||
|
for (const it of value) {
|
||||||
|
yield [transform(it), it];
|
||||||
|
}
|
||||||
|
}
|
||||||
5
src/sequence/associateWith.ts
Normal file
5
src/sequence/associateWith.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export function* associateWith<T, V>(value: Iterable<T>, transform: (it: T) => V): Iterable<[T, V]> {
|
||||||
|
for (const it of value) {
|
||||||
|
yield [it, transform(it)];
|
||||||
|
}
|
||||||
|
}
|
||||||
9
src/sequence/average.ts
Normal file
9
src/sequence/average.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
export function average(value: Iterable<number>): number {
|
||||||
|
let count = 0;
|
||||||
|
let sum = 0;
|
||||||
|
for (const it of value) {
|
||||||
|
count++;
|
||||||
|
sum += it;
|
||||||
|
}
|
||||||
|
return count !== 0 ? sum / count : 0;
|
||||||
|
}
|
||||||
9
src/sequence/averageBy.ts
Normal file
9
src/sequence/averageBy.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
export function averageBy<T>(value: Iterable<T>, transform: (it: T) => number): number {
|
||||||
|
let count = 0;
|
||||||
|
let sum = 0;
|
||||||
|
for (const it of value) {
|
||||||
|
count++;
|
||||||
|
sum += transform(it);
|
||||||
|
}
|
||||||
|
return count !== 0 ? sum / count : 0;
|
||||||
|
}
|
||||||
11
src/sequence/chunked.ts
Normal file
11
src/sequence/chunked.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
export function* chunked<T>(value: Iterable<T>, size: number): Iterable<T[]> {
|
||||||
|
let buffer: T[] = [];
|
||||||
|
for (const it of value) {
|
||||||
|
buffer.push(it);
|
||||||
|
if (buffer.length === size) {
|
||||||
|
yield buffer;
|
||||||
|
buffer = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (buffer.length !== 0) yield buffer;
|
||||||
|
}
|
||||||
3
src/sequence/collect.ts
Normal file
3
src/sequence/collect.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export function collect<T>(value: Iterable<T>): T[] {
|
||||||
|
return [...value];
|
||||||
|
}
|
||||||
6
src/sequence/contains.ts
Normal file
6
src/sequence/contains.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export function contains<T>(value: Iterable<T>, item: T): boolean {
|
||||||
|
for (const it of value) {
|
||||||
|
if (it === item) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
7
src/sequence/containsAll.ts
Normal file
7
src/sequence/containsAll.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export function containsAll<T>(value: Iterable<T>, items: Iterable<T>): boolean {
|
||||||
|
const set = new Set(items);
|
||||||
|
for (const it of value) {
|
||||||
|
set.delete(it);
|
||||||
|
}
|
||||||
|
return set.size === 0;
|
||||||
|
}
|
||||||
7
src/sequence/count.ts
Normal file
7
src/sequence/count.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export function count<T>(value: Iterable<T>, predicate?: (it: T) => boolean): number {
|
||||||
|
let count = 0;
|
||||||
|
for (const it of value) {
|
||||||
|
if (!predicate || predicate(it)) count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
8
src/sequence/distinct.ts
Normal file
8
src/sequence/distinct.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
export function* distinct<T>(value: Iterable<T>): Iterable<T> {
|
||||||
|
const set: Set<T> = new Set();
|
||||||
|
for (const it of value) {
|
||||||
|
if (set.has(it)) continue;
|
||||||
|
set.add(it);
|
||||||
|
yield it;
|
||||||
|
}
|
||||||
|
}
|
||||||
9
src/sequence/distinctBy.ts
Normal file
9
src/sequence/distinctBy.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
export function* distinctBy<T, K>(value: Iterable<T>, transform: (it: T) => K): Iterable<T> {
|
||||||
|
const set: Set<K> = new Set();
|
||||||
|
for (const it of value) {
|
||||||
|
const x = transform(it);
|
||||||
|
if (set.has(x)) continue;
|
||||||
|
set.add(x);
|
||||||
|
yield it;
|
||||||
|
}
|
||||||
|
}
|
||||||
7
src/sequence/drop.ts
Normal file
7
src/sequence/drop.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export function* drop<T>(value: Iterable<T>, count: number): Iterable<T> {
|
||||||
|
let dropped = 0;
|
||||||
|
for (const it of value) {
|
||||||
|
if (dropped === count) yield it;
|
||||||
|
else dropped++;
|
||||||
|
}
|
||||||
|
}
|
||||||
12
src/sequence/dropUntil.ts
Normal file
12
src/sequence/dropUntil.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
export function* dropUntil<T>(value: Iterable<T>, predicate: (it: T) => boolean): Iterable<T> {
|
||||||
|
const iterator = value[Symbol.iterator]();
|
||||||
|
let {value: it, done} = iterator.next();
|
||||||
|
while (!done) {
|
||||||
|
if (predicate(it)) break;
|
||||||
|
({value: it, done} = iterator.next());
|
||||||
|
}
|
||||||
|
while (!done) {
|
||||||
|
yield it;
|
||||||
|
({value: it, done} = iterator.next());
|
||||||
|
}
|
||||||
|
}
|
||||||
12
src/sequence/dropWhile.ts
Normal file
12
src/sequence/dropWhile.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
export function* dropWhile<T>(value: Iterable<T>, predicate: (it: T) => boolean): Iterable<T> {
|
||||||
|
const iterator = value[Symbol.iterator]();
|
||||||
|
let {value: it, done} = iterator.next();
|
||||||
|
while (!done) {
|
||||||
|
if (!predicate(it)) break;
|
||||||
|
({value: it, done} = iterator.next());
|
||||||
|
}
|
||||||
|
while (!done) {
|
||||||
|
yield it;
|
||||||
|
({value: it, done} = iterator.next());
|
||||||
|
}
|
||||||
|
}
|
||||||
5
src/sequence/filter.ts
Normal file
5
src/sequence/filter.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export function* filter<T>(value: Iterable<T>, predicate: (it: T) => boolean): Iterable<T> {
|
||||||
|
for (const it of value) {
|
||||||
|
if (predicate(it)) yield it;
|
||||||
|
}
|
||||||
|
}
|
||||||
6
src/sequence/filterIndexed.ts
Normal file
6
src/sequence/filterIndexed.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export function* filterIndexed<T>(value: Iterable<T>, predicate: (index: number, it: T) => boolean): Iterable<T> {
|
||||||
|
let index = 0;
|
||||||
|
for (const it of value) {
|
||||||
|
if (predicate(index++, it)) yield it;
|
||||||
|
}
|
||||||
|
}
|
||||||
8
src/sequence/first.ts
Normal file
8
src/sequence/first.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import {error} from "../util/error.js";
|
||||||
|
|
||||||
|
export function first<T>(value: Iterable<T>, predicate?: (it: T) => boolean): T {
|
||||||
|
for (const it of value) {
|
||||||
|
if (!predicate || predicate(it)) return it;
|
||||||
|
}
|
||||||
|
error();
|
||||||
|
}
|
||||||
10
src/sequence/firstIndex.ts
Normal file
10
src/sequence/firstIndex.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import {error} from "../util/error.js";
|
||||||
|
|
||||||
|
export function firstIndex<T>(value: Iterable<T>, predicate?: (it: T) => boolean): number {
|
||||||
|
let index = 0;
|
||||||
|
for (const it of value) {
|
||||||
|
if (!predicate || predicate(it)) return index;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
error();
|
||||||
|
}
|
||||||
8
src/sequence/firstIndexOrNull.ts
Normal file
8
src/sequence/firstIndexOrNull.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
export function firstIndexOrNull<T>(value: Iterable<T>, predicate?: (it: T) => boolean): number | null {
|
||||||
|
let index = 0;
|
||||||
|
for (const it of value) {
|
||||||
|
if (!predicate || predicate(it)) return index;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
6
src/sequence/firstOrNull.ts
Normal file
6
src/sequence/firstOrNull.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export function firstOrNull<T>(value: Iterable<T>, predicate?: (it: T) => boolean): T | null {
|
||||||
|
for (const it of value) {
|
||||||
|
if (!predicate || predicate(it)) return it;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
5
src/sequence/flatMap.ts
Normal file
5
src/sequence/flatMap.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export function* flatMap<T, R>(value: Iterable<T>, transform: (it: T) => Iterable<R>): Iterable<R> {
|
||||||
|
for (const it of value) {
|
||||||
|
yield* transform(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
6
src/sequence/flatMapIndexed.ts
Normal file
6
src/sequence/flatMapIndexed.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export function* flatMapIndexed<T, R>(value: Iterable<T>, transform: (index: number, it: T) => Iterable<R>): Iterable<R> {
|
||||||
|
let index = 0;
|
||||||
|
for (const it of value) {
|
||||||
|
yield* transform(index++, it);
|
||||||
|
}
|
||||||
|
}
|
||||||
5
src/sequence/flatten.ts
Normal file
5
src/sequence/flatten.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export function* flatten<R>(value: Iterable<Iterable<R>>): Iterable<R> {
|
||||||
|
for (const it of value) {
|
||||||
|
yield* it;
|
||||||
|
}
|
||||||
|
}
|
||||||
7
src/sequence/fold.ts
Normal file
7
src/sequence/fold.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export function fold<T, R>(value: Iterable<T>, initial: R, accumulate: (acc: R, it: T) => R): R {
|
||||||
|
let acc = initial;
|
||||||
|
for (const it of value) {
|
||||||
|
acc = accumulate(acc, it);
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
5
src/sequence/forEach.ts
Normal file
5
src/sequence/forEach.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export function forEach<T>(value: Iterable<T>, action: (it: T) => void) {
|
||||||
|
for (const it of value) {
|
||||||
|
action(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
9
src/sequence/get.ts
Normal file
9
src/sequence/get.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import {error} from "../util/error.js";
|
||||||
|
|
||||||
|
export function get<T>(value: Iterable<T>, index: number): T {
|
||||||
|
let i = 0;
|
||||||
|
for (const it of value) {
|
||||||
|
if (i++ === index) return it;
|
||||||
|
}
|
||||||
|
error();
|
||||||
|
}
|
||||||
7
src/sequence/getOrNull.ts
Normal file
7
src/sequence/getOrNull.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export function getOrNull<T>(value: Iterable<T>, index: number): T | null {
|
||||||
|
let i = 0;
|
||||||
|
for (const it of value) {
|
||||||
|
if (i++ === index) return it;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
9
src/sequence/groupBy.ts
Normal file
9
src/sequence/groupBy.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
export function groupBy<T, K>(value: Iterable<T>, transform: (it: T) => K): [K, T[]][] {
|
||||||
|
const map: Map<K, T[]> = new Map();
|
||||||
|
for (const it of value) {
|
||||||
|
const key = transform(it);
|
||||||
|
if (!map.has(key)) map.set(key, []);
|
||||||
|
map.get(key)!.push(it);
|
||||||
|
}
|
||||||
|
return [...map];
|
||||||
|
}
|
||||||
6
src/sequence/indices.ts
Normal file
6
src/sequence/indices.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export function* indices(value: Iterable<unknown>): Iterable<number> {
|
||||||
|
let index = 0;
|
||||||
|
for (const _ of value) {
|
||||||
|
yield index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
4
src/sequence/isEmpty.ts
Normal file
4
src/sequence/isEmpty.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export function isEmpty<T>(value: Iterable<T>): boolean {
|
||||||
|
const {done} = value[Symbol.iterator]().next();
|
||||||
|
return done ?? false;
|
||||||
|
}
|
||||||
4
src/sequence/isNotEmpty.ts
Normal file
4
src/sequence/isNotEmpty.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export function isNotEmpty<T>(value: Iterable<T>): boolean {
|
||||||
|
const {done} = value[Symbol.iterator]().next();
|
||||||
|
return !(done ?? false);
|
||||||
|
}
|
||||||
7
src/sequence/joinToString.ts
Normal file
7
src/sequence/joinToString.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export function joinToString<T>(value: Iterable<T>, separator: string, transform?: (it: T) => string): string {
|
||||||
|
const transformed: string[] = [];
|
||||||
|
for (const it of value) {
|
||||||
|
transformed.push(transform ? transform(it) : String(it));
|
||||||
|
}
|
||||||
|
return transformed.join(separator);
|
||||||
|
}
|
||||||
13
src/sequence/last.ts
Normal file
13
src/sequence/last.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import {error} from "../util/error.js";
|
||||||
|
|
||||||
|
export function last<T>(value: Iterable<T>, predicate?: (it: T) => boolean): T {
|
||||||
|
let last!: T;
|
||||||
|
let found = false;
|
||||||
|
for (const it of value) {
|
||||||
|
if (predicate && !predicate(it)) continue;
|
||||||
|
last = it;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
if (!found) error();
|
||||||
|
return last;
|
||||||
|
}
|
||||||
12
src/sequence/lastIndex.ts
Normal file
12
src/sequence/lastIndex.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import {error} from "../util/error.js";
|
||||||
|
|
||||||
|
export function lastIndex<T>(value: Iterable<T>, predicate?: (it: T) => boolean): number {
|
||||||
|
let last: number | undefined;
|
||||||
|
let index = 0;
|
||||||
|
for (const it of value) {
|
||||||
|
if (!predicate || predicate(it)) last = index;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
if (last === undefined) error();
|
||||||
|
return last;
|
||||||
|
}
|
||||||
10
src/sequence/lastIndexOrNull.ts
Normal file
10
src/sequence/lastIndexOrNull.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
export function lastIndexOrNull<T>(value: Iterable<T>, predicate?: (it: T) => boolean): number | null {
|
||||||
|
let last: number | undefined;
|
||||||
|
let index = 0;
|
||||||
|
for (const it of value) {
|
||||||
|
if (!predicate || predicate(it)) last = index;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
if (last === undefined) return null;
|
||||||
|
return last;
|
||||||
|
}
|
||||||
11
src/sequence/lastOrNull.ts
Normal file
11
src/sequence/lastOrNull.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
export function lastOrNull<T>(value: Iterable<T>, predicate?: (it: T) => boolean): T | null {
|
||||||
|
let last!: T;
|
||||||
|
let found = false;
|
||||||
|
for (const it of value) {
|
||||||
|
if (predicate && !predicate(it)) continue;
|
||||||
|
last = it;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
if (!found) return null;
|
||||||
|
return last;
|
||||||
|
}
|
||||||
5
src/sequence/map.ts
Normal file
5
src/sequence/map.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export function* map<T, R>(value: Iterable<T>, transform: (it: T) => R): Iterable<R> {
|
||||||
|
for (const it of value) {
|
||||||
|
yield transform(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
6
src/sequence/mapIndexed.ts
Normal file
6
src/sequence/mapIndexed.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export function* mapIndexed<T, R>(value: Iterable<T>, transform: (index: number, it: T) => R): Iterable<R> {
|
||||||
|
let index = 0;
|
||||||
|
for (const it of value) {
|
||||||
|
yield transform(index++, it);
|
||||||
|
}
|
||||||
|
}
|
||||||
13
src/sequence/max.ts
Normal file
13
src/sequence/max.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import {error} from "../util/error.js";
|
||||||
|
|
||||||
|
export function max(value: Iterable<number>): number {
|
||||||
|
let max!: number;
|
||||||
|
let found = false;
|
||||||
|
for (const it of value) {
|
||||||
|
if (found && it <= max) continue;
|
||||||
|
max = it;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
if (!found) error();
|
||||||
|
return max;
|
||||||
|
}
|
||||||
16
src/sequence/maxBy.ts
Normal file
16
src/sequence/maxBy.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import {error} from "../util/error.js";
|
||||||
|
|
||||||
|
export function maxBy<T>(value: Iterable<T>, transform: (it: T) => number): T {
|
||||||
|
let maxIt!: T;
|
||||||
|
let max!: number;
|
||||||
|
let found = false;
|
||||||
|
for (const it of value) {
|
||||||
|
const val = transform(it);
|
||||||
|
if (found && val <= max) continue;
|
||||||
|
maxIt = it;
|
||||||
|
max = val;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
if (!found) error();
|
||||||
|
return maxIt;
|
||||||
|
}
|
||||||
14
src/sequence/maxByOrNull.ts
Normal file
14
src/sequence/maxByOrNull.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
export function maxByOrNull<T>(value: Iterable<T>, transform: (it: T) => number): T | null {
|
||||||
|
let maxIt!: T;
|
||||||
|
let max!: number;
|
||||||
|
let found = false;
|
||||||
|
for (const it of value) {
|
||||||
|
const val = transform(it);
|
||||||
|
if (found && val <= max) continue;
|
||||||
|
maxIt = it;
|
||||||
|
max = val;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
if (!found) return null;
|
||||||
|
return maxIt;
|
||||||
|
}
|
||||||
14
src/sequence/maxOf.ts
Normal file
14
src/sequence/maxOf.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import {error} from "../util/error.js";
|
||||||
|
|
||||||
|
export function maxOf<T>(value: Iterable<T>, transform: (it: T) => number): number {
|
||||||
|
let max!: number;
|
||||||
|
let found = false;
|
||||||
|
for (const it of value) {
|
||||||
|
const val = transform(it);
|
||||||
|
if (found && val <= max) continue;
|
||||||
|
max = val;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
if (!found) error();
|
||||||
|
return max;
|
||||||
|
}
|
||||||
12
src/sequence/maxOfOrNull.ts
Normal file
12
src/sequence/maxOfOrNull.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
export function maxOfOrNull<T>(value: Iterable<T>, transform: (it: T) => number): number | null {
|
||||||
|
let max!: number;
|
||||||
|
let found = false;
|
||||||
|
for (const it of value) {
|
||||||
|
const val = transform(it);
|
||||||
|
if (found && val <= max) continue;
|
||||||
|
max = val;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
if (!found) return null;
|
||||||
|
return max;
|
||||||
|
}
|
||||||
11
src/sequence/maxOrNull.ts
Normal file
11
src/sequence/maxOrNull.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
export function maxOrNull(value: Iterable<number>): number | null {
|
||||||
|
let max!: number;
|
||||||
|
let found = false;
|
||||||
|
for (const it of value) {
|
||||||
|
if (found && it <= max) continue;
|
||||||
|
max = it;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
if (!found) return null;
|
||||||
|
return max;
|
||||||
|
}
|
||||||
13
src/sequence/maxWith.ts
Normal file
13
src/sequence/maxWith.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import {error} from "../util/error.js";
|
||||||
|
|
||||||
|
export function maxWith<T>(value: Iterable<T>, compare: (a: T, b: T) => number): T {
|
||||||
|
let max!: T;
|
||||||
|
let found = false;
|
||||||
|
for (const it of value) {
|
||||||
|
if (found && compare(it, max) <= 0) continue;
|
||||||
|
max = it;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
if (!found) error();
|
||||||
|
return max;
|
||||||
|
}
|
||||||
11
src/sequence/maxWithOrNull.ts
Normal file
11
src/sequence/maxWithOrNull.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
export function maxWithOrNull<T>(value: Iterable<T>, compare: (a: T, b: T) => number): T | null {
|
||||||
|
let max!: T;
|
||||||
|
let found = false;
|
||||||
|
for (const it of value) {
|
||||||
|
if (found && compare(it, max) <= 0) continue;
|
||||||
|
max = it;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
if (!found) return null;
|
||||||
|
return max;
|
||||||
|
}
|
||||||
13
src/sequence/min.ts
Normal file
13
src/sequence/min.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import {error} from "../util/error.js";
|
||||||
|
|
||||||
|
export function min(value: Iterable<number>): number {
|
||||||
|
let min!: number;
|
||||||
|
let found = false;
|
||||||
|
for (const it of value) {
|
||||||
|
if (found && it >= min) continue;
|
||||||
|
min = it;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
if (!found) error();
|
||||||
|
return min;
|
||||||
|
}
|
||||||
16
src/sequence/minBy.ts
Normal file
16
src/sequence/minBy.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import {error} from "../util/error.js";
|
||||||
|
|
||||||
|
export function minBy<T>(value: Iterable<T>, transform: (it: T) => number): T {
|
||||||
|
let minIt!: T;
|
||||||
|
let min!: number;
|
||||||
|
let found = false;
|
||||||
|
for (const it of value) {
|
||||||
|
const val = transform(it);
|
||||||
|
if (found && val >= min) continue;
|
||||||
|
minIt = it;
|
||||||
|
min = val;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
if (!found) error();
|
||||||
|
return minIt;
|
||||||
|
}
|
||||||
14
src/sequence/minByOrNull.ts
Normal file
14
src/sequence/minByOrNull.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
export function minByOrNull<T>(value: Iterable<T>, transform: (it: T) => number): T | null {
|
||||||
|
let minIt!: T;
|
||||||
|
let min!: number;
|
||||||
|
let found = false;
|
||||||
|
for (const it of value) {
|
||||||
|
const val = transform(it);
|
||||||
|
if (found && val >= min) continue;
|
||||||
|
minIt = it;
|
||||||
|
min = val;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
if (!found) return null;
|
||||||
|
return minIt;
|
||||||
|
}
|
||||||
14
src/sequence/minOf.ts
Normal file
14
src/sequence/minOf.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import {error} from "../util/error.js";
|
||||||
|
|
||||||
|
export function minOf<T>(value: Iterable<T>, transform: (it: T) => number): number {
|
||||||
|
let min!: number;
|
||||||
|
let found = false;
|
||||||
|
for (const it of value) {
|
||||||
|
const val = transform(it);
|
||||||
|
if (found && val >= min) continue;
|
||||||
|
min = val;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
if (!found) error();
|
||||||
|
return min;
|
||||||
|
}
|
||||||
12
src/sequence/minOfOrNull.ts
Normal file
12
src/sequence/minOfOrNull.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
export function minOfOrNull<T>(value: Iterable<T>, transform: (it: T) => number): number | null {
|
||||||
|
let min!: number;
|
||||||
|
let found = false;
|
||||||
|
for (const it of value) {
|
||||||
|
const val = transform(it);
|
||||||
|
if (found && val >= min) continue;
|
||||||
|
min = val;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
if (!found) return null;
|
||||||
|
return min;
|
||||||
|
}
|
||||||
11
src/sequence/minOrNull.ts
Normal file
11
src/sequence/minOrNull.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
export function minOrNull(value: Iterable<number>): number | null {
|
||||||
|
let min!: number;
|
||||||
|
let found = false;
|
||||||
|
for (const it of value) {
|
||||||
|
if (found && it <= min) continue;
|
||||||
|
min = it;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
if (!found) return null;
|
||||||
|
return min;
|
||||||
|
}
|
||||||
14
src/sequence/minWith.ts
Normal file
14
src/sequence/minWith.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import {error} from "../util/error.js";
|
||||||
|
|
||||||
|
export function minWith<T>(value: Iterable<T>, compare: (a: T, b: T) => number): T {
|
||||||
|
const iterator = value[Symbol.iterator]();
|
||||||
|
let {value: it, done} = iterator.next();
|
||||||
|
if (done) error();
|
||||||
|
let min = it;
|
||||||
|
({value: it, done} = iterator.next());
|
||||||
|
while (!done) {
|
||||||
|
if (compare(it, min) < 0) min = it;
|
||||||
|
({value: it, done} = iterator.next());
|
||||||
|
}
|
||||||
|
return min;
|
||||||
|
}
|
||||||
12
src/sequence/minWithOrNull.ts
Normal file
12
src/sequence/minWithOrNull.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
export function minWithOrNull<T>(value: Iterable<T>, compare: (a: T, b: T) => number): T | null {
|
||||||
|
const iterator = value[Symbol.iterator]();
|
||||||
|
let {value: it, done} = iterator.next();
|
||||||
|
if (done) return null;
|
||||||
|
let min = it;
|
||||||
|
({value: it, done} = iterator.next());
|
||||||
|
while (!done) {
|
||||||
|
if (compare(it, min) < 0) min = it;
|
||||||
|
({value: it, done} = iterator.next());
|
||||||
|
}
|
||||||
|
return min;
|
||||||
|
}
|
||||||
6
src/sequence/minus.ts
Normal file
6
src/sequence/minus.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export function* minus<T>(value: Iterable<T>, items: Iterable<T>): Iterable<T> {
|
||||||
|
const set = new Set(items);
|
||||||
|
for (const it of value) {
|
||||||
|
if (!set.has(it)) yield it;
|
||||||
|
}
|
||||||
|
}
|
||||||
6
src/sequence/none.ts
Normal file
6
src/sequence/none.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export function none<T>(value: Iterable<T>, predicate: (it: T) => boolean): boolean {
|
||||||
|
for (const it of value) {
|
||||||
|
if (predicate(it)) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
6
src/sequence/onEach.ts
Normal file
6
src/sequence/onEach.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export function* onEach<T>(value: Iterable<T>, action: (it: T) => void): Iterable<T> {
|
||||||
|
for (const it of value) {
|
||||||
|
action(it);
|
||||||
|
yield it;
|
||||||
|
}
|
||||||
|
}
|
||||||
9
src/sequence/partition.ts
Normal file
9
src/sequence/partition.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
export function partition<T>(value: Iterable<T>, predicate: (it: T) => boolean): [T[], T[]] {
|
||||||
|
const t: T[] = [];
|
||||||
|
const f: T[] = [];
|
||||||
|
for (const it of value) {
|
||||||
|
if (predicate(it)) t.push(it);
|
||||||
|
else f.push(it);
|
||||||
|
}
|
||||||
|
return [t, f];
|
||||||
|
}
|
||||||
8
src/sequence/plus.ts
Normal file
8
src/sequence/plus.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
export function* plus<T>(value1: Iterable<T>, value2: Iterable<T>): Iterable<T> {
|
||||||
|
for (const it of value1) {
|
||||||
|
yield it;
|
||||||
|
}
|
||||||
|
for (const it of value2) {
|
||||||
|
yield it;
|
||||||
|
}
|
||||||
|
}
|
||||||
14
src/sequence/reduce.ts
Normal file
14
src/sequence/reduce.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import {error} from "../util/error.js";
|
||||||
|
|
||||||
|
export function reduce<T>(value: Iterable<T>, accumulate: (acc: T, it: T) => T): T {
|
||||||
|
const iterator = value[Symbol.iterator]();
|
||||||
|
let {value: it, done} = iterator.next();
|
||||||
|
if (done) error();
|
||||||
|
let acc = it
|
||||||
|
({value: it, done} = iterator.next());
|
||||||
|
while (!done) {
|
||||||
|
acc = accumulate(acc, it);
|
||||||
|
({value: it, done} = iterator.next());
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
12
src/sequence/reduceOrNull.ts
Normal file
12
src/sequence/reduceOrNull.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
export function reduceOrNull<T>(value: Iterable<T>, accumulate: (acc: T, it: T) => T): T | null {
|
||||||
|
const iterator = value[Symbol.iterator]();
|
||||||
|
let {value: it, done} = iterator.next();
|
||||||
|
if (done) return null;
|
||||||
|
let acc = it
|
||||||
|
({value: it, done} = iterator.next());
|
||||||
|
while (!done) {
|
||||||
|
acc = accumulate(acc, it);
|
||||||
|
({value: it, done} = iterator.next());
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
3
src/sequence/reversed.ts
Normal file
3
src/sequence/reversed.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export function reversed<T>(iterable: Iterable<T>): T[] {
|
||||||
|
return [...iterable].reverse();
|
||||||
|
}
|
||||||
8
src/sequence/scan.ts
Normal file
8
src/sequence/scan.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
export function* scan<T, R>(value: Iterable<T>, initial: R, accumulate: (acc: R, it: T) => R): Iterable<R> {
|
||||||
|
let acc = initial;
|
||||||
|
yield acc;
|
||||||
|
for (const it of value) {
|
||||||
|
acc = accumulate(acc, it);
|
||||||
|
yield acc;
|
||||||
|
}
|
||||||
|
}
|
||||||
14
src/sequence/single.ts
Normal file
14
src/sequence/single.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import {error} from "../util/error.js";
|
||||||
|
|
||||||
|
export function single<T>(value: Iterable<T>, predicate?: (it: T) => boolean): T {
|
||||||
|
let last!: T;
|
||||||
|
let found = false;
|
||||||
|
for (const it of value) {
|
||||||
|
if (predicate && !predicate(it)) continue;
|
||||||
|
if (found) error();
|
||||||
|
last = it;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
if (!found) error();
|
||||||
|
return last;
|
||||||
|
}
|
||||||
12
src/sequence/singleOrNull.ts
Normal file
12
src/sequence/singleOrNull.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
export function singleOrNull<T>(value: Iterable<T>, predicate?: (it: T) => boolean): T | null {
|
||||||
|
let last!: T;
|
||||||
|
let found = false;
|
||||||
|
for (const it of value) {
|
||||||
|
if (predicate && !predicate(it)) continue;
|
||||||
|
if (found) return null;
|
||||||
|
last = it;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
if (!found) return null;
|
||||||
|
return last;
|
||||||
|
}
|
||||||
7
src/sequence/slice.ts
Normal file
7
src/sequence/slice.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export function* slice<T>(value: Iterable<T>, start: number, endInclusive?: number): Iterable<T> {
|
||||||
|
let index = 0;
|
||||||
|
for (const it of value) {
|
||||||
|
if (endInclusive !== undefined && index > endInclusive) return;
|
||||||
|
if (index++ >= start) yield it;
|
||||||
|
}
|
||||||
|
}
|
||||||
3
src/sequence/sorted.ts
Normal file
3
src/sequence/sorted.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export function sorted(iterable: Iterable<number>): number[] {
|
||||||
|
return [...iterable].sort((a, b) => a - b);
|
||||||
|
}
|
||||||
3
src/sequence/sortedBy.ts
Normal file
3
src/sequence/sortedBy.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export function sortedBy<T>(iterable: Iterable<T>, transform: (it: T) => number): T[] {
|
||||||
|
return [...iterable].sort((a, b) => transform(a) - transform(b));
|
||||||
|
}
|
||||||
3
src/sequence/sortedWith.ts
Normal file
3
src/sequence/sortedWith.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export function sortedWith<T>(iterable: Iterable<T>, compare: (a: T, b: T) => number): T[] {
|
||||||
|
return [...iterable].sort(compare);
|
||||||
|
}
|
||||||
7
src/sequence/sum.ts
Normal file
7
src/sequence/sum.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export function sum(value: Iterable<number>): number {
|
||||||
|
let sum = 0;
|
||||||
|
for (const it of value) {
|
||||||
|
sum += it;
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
7
src/sequence/sumBy.ts
Normal file
7
src/sequence/sumBy.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export function sumBy<T>(value: Iterable<T>, transform: (it: T) => number): number {
|
||||||
|
let sum = 0;
|
||||||
|
for (const it of value) {
|
||||||
|
sum += transform(it);
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
7
src/sequence/take.ts
Normal file
7
src/sequence/take.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export function* take<T>(value: Iterable<T>, count: number): Iterable<T> {
|
||||||
|
let taken = 0;
|
||||||
|
for (const it of value) {
|
||||||
|
if (taken++ === count) return;
|
||||||
|
yield it;
|
||||||
|
}
|
||||||
|
}
|
||||||
6
src/sequence/takeUntil.ts
Normal file
6
src/sequence/takeUntil.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export function* takeUntil<T>(value: Iterable<T>, predicate: (it: T) => boolean): Iterable<T> {
|
||||||
|
for (const it of value) {
|
||||||
|
if (predicate(it)) return;
|
||||||
|
yield it;
|
||||||
|
}
|
||||||
|
}
|
||||||
6
src/sequence/takeWhile.ts
Normal file
6
src/sequence/takeWhile.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export function* takeWhile<T>(value: Iterable<T>, predicate: (it: T) => boolean): Iterable<T> {
|
||||||
|
for (const it of value) {
|
||||||
|
if (!predicate(it)) return;
|
||||||
|
yield it;
|
||||||
|
}
|
||||||
|
}
|
||||||
12
src/sequence/unzip.ts
Normal file
12
src/sequence/unzip.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
export function unzip<A, B>(value: Iterable<[A, B]>): [A[], B[]] {
|
||||||
|
const a: A[] = [];
|
||||||
|
const b: B[] = [];
|
||||||
|
const iterator = value[Symbol.iterator]();
|
||||||
|
let {value: it, done} = iterator.next();
|
||||||
|
while (!done) {
|
||||||
|
a.push(it[0]);
|
||||||
|
b.push(it[1]);
|
||||||
|
({value: it, done} = iterator.next());
|
||||||
|
}
|
||||||
|
return [a, b];
|
||||||
|
}
|
||||||
15
src/sequence/windowed.ts
Normal file
15
src/sequence/windowed.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
export function* windowed<T>(value: Iterable<T>, size: number, step: number = 1, partial: boolean = false): Iterable<T[]> {
|
||||||
|
const buffer: T[] = [];
|
||||||
|
for (const it of value) {
|
||||||
|
buffer.push(it);
|
||||||
|
if (buffer.length === size) {
|
||||||
|
yield [...buffer];
|
||||||
|
buffer.splice(0, step);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!partial) return;
|
||||||
|
while (buffer.length !== 0) {
|
||||||
|
yield [...buffer];
|
||||||
|
buffer.splice(0, step);
|
||||||
|
}
|
||||||
|
}
|
||||||
6
src/sequence/withIndex.ts
Normal file
6
src/sequence/withIndex.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export function* withIndex<T>(value: Iterable<T>): Iterable<[number, T]> {
|
||||||
|
let index = 0;
|
||||||
|
for (const it of value) {
|
||||||
|
yield [index++, it];
|
||||||
|
}
|
||||||
|
}
|
||||||
9
src/sequence/zip.ts
Normal file
9
src/sequence/zip.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
export function* zip<T, B>(value: Iterable<T>, items: Iterable<B>): Iterable<[T, B]> {
|
||||||
|
const iteratorA = value[Symbol.iterator]();
|
||||||
|
const iteratorB = items[Symbol.iterator]();
|
||||||
|
let {value: itA, done: doneA} = iteratorA.next();
|
||||||
|
let {value: itB, done: doneB} = iteratorB.next();
|
||||||
|
while (!doneA && !doneB) {
|
||||||
|
yield [itA, itB];
|
||||||
|
}
|
||||||
|
}
|
||||||
3
src/util/error.ts
Normal file
3
src/util/error.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export function error(message?: string): never {
|
||||||
|
throw Error(message);
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"moduleResolution": "NodeNext",
|
|
||||||
"module": "NodeNext",
|
"module": "NodeNext",
|
||||||
|
"moduleResolution": "NodeNext",
|
||||||
"target": "ESNext",
|
"target": "ESNext",
|
||||||
"rootDir": "./src/",
|
"rootDir": "./src/",
|
||||||
"outDir": "./dist/",
|
"outDir": "./dist/",
|
||||||
|
|||||||
Reference in New Issue
Block a user