Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import {
- AggregateFunction,
- CompareFunction,
- EqualityFunction,
- PredicateFunction,
- ResultFunction,
- SelectFunction,
- IndexedSelectFunction,
- IndexedSelectManyFunction,
- selectFn,
- resultFn,
- predicateFn,
- equalityFn,
- compareFn,
- generatorFn
- } from './util'
- export interface EnumerableConstructor {
- new<TSource> (iterator: () => IterableIterator<TSource>): Enumerable<TSource>
- new<TSource> (iterator: () => IterableIterator<TSource>, compare: undefined): Enumerable<TSource>
- new<TSource> (iterator: () => IterableIterator<TSource>, compare: CompareFunction<TSource>): OrderedEnumerable<TSource>
- new (iterator: () => IterableIterator<any>): Enumerable<any>
- new (iterator: () => IterableIterator<any>, compare: undefined): Enumerable<any>
- new (iterator: () => IterableIterator<any>, compare: CompareFunction<any>): OrderedEnumerable<any>
- empty<TSource> (): Enumerable<TSource>
- isEnumerable<TSource> (iterable: Iterable<TSource> | ArrayLike<TSource>): iterable is Enumerable<TSource>
- range (start: number, count: number): Enumerable<number> | never
- repeat<TSource> (element: TSource, count: number): Enumerable<TSource>
- }
- export interface GroupingConstructor extends EnumerableConstructor {
- new<TSource, TKey> (iterator: () => IterableIterator<TSource>, key: TKey): Grouping<TKey, TSource>
- new<TSource, TKey> (iterator: () => IterableIterator<TSource>, compare: undefined, key: TKey): Grouping<TSource, TKey>
- new<TSource, TKey> (iterator: () => IterableIterator<TSource>, compare: CompareFunction<TSource>, key: TKey): OrderedGrouping<TKey, TSource>
- new<TKey> (iterator: () => IterableIterator<any>, key: TKey): Grouping<TKey, any>
- new<TKey> (iterator: () => IterableIterator<any>, compare: undefined, key: TKey): Grouping<TKey, any>
- new<TKey> (iterator: () => IterableIterator<any>, compare: CompareFunction<any>, key: TKey): OrderedGrouping<TKey, any>
- }
- export interface OrderedEnumerable<TSource> extends Enumerable<TSource> {
- defaultIfEmpty (this: OrderedEnumerable<TSource>, element: TSource): OrderedEnumerable<TSource>
- distinct (this: OrderedEnumerable<TSource>, equality: EqualityFunction<TSource>): OrderedEnumerable<TSource>
- except (this: OrderedEnumerable<TSource>, second: Enumerable<TSource>, equality: EqualityFunction<TSource>): OrderedEnumerable<TSource>
- groupBy<TKey> (this: OrderedEnumerable<TSource>, selectKey: IndexedSelectFunction<TSource, TKey>): Enumerable<OrderedGrouping<TKey, TSource>>
- groupBy<TKey, TElement> (this: OrderedEnumerable<TSource>, selectKey: IndexedSelectFunction<TSource, TKey>, selectElement: IndexedSelectFunction<TSource, TElement>): Enumerable<OrderedGrouping<TKey, TElement>>
- intersect (this: OrderedEnumerable<TSource>, second: Enumerable<TSource>, equality?: EqualityFunction<TSource>): OrderedEnumerable<TSource>
- skip (this: OrderedEnumerable<TSource>, count: number): OrderedEnumerable<TSource>
- skipLast (this: OrderedEnumerable<TSource>, count: number): OrderedEnumerable<TSource>
- skipWhile (this: OrderedEnumerable<TSource>, predicate: PredicateFunction<TSource>): OrderedEnumerable<TSource>
- take (this: OrderedEnumerable<TSource>, count: number): OrderedEnumerable<TSource>
- takeLast (this: OrderedEnumerable<TSource>, count: number): OrderedEnumerable<TSource>
- takeWhile (this: OrderedEnumerable<TSource>, predicate: PredicateFunction<TSource>): OrderedEnumerable<TSource>
- where (this: OrderedEnumerable<TSource>, predicate: PredicateFunction<TSource>): OrderedEnumerable<TSource>
- }
- export interface OrderedGrouping<TKey, TSource> extends OrderedEnumerable<TSource> {
- readonly key: TKey
- }
- const isEnumerable = <TSource> (iterable: Iterable<TSource> | ConcatArray<TSource>): iterable is Enumerable<TSource> => iterable.constructor === Enumerable
- const aggregateImpl = <TSource, TResult> (iterator: IterableIterator<TSource>, accumulator: TResult, aggregate: AggregateFunction<TSource, TResult>, index: number, source: Enumerable<TSource>) => {
- for (const value of iterator) {
- accumulator = aggregate(accumulator, value, index++, source)
- }
- return accumulator
- }
- const aggregateRightImpl = <TSource, TResult> (array: TSource[], accumulator: TResult, aggregate: AggregateFunction<TSource, TResult>, index: number, source: Enumerable<TSource>) => {
- while (index >= 0) {
- accumulator = aggregate(accumulator, array[index], index--, source)
- }
- return accumulator
- }
- const selectEntry = <TSource, TKey, TValue> (selectKey: IndexedSelectFunction<TSource, TKey>, selectValue: IndexedSelectFunction<TSource, TValue>): IndexedSelectFunction<TSource, [TKey, TValue]> => (value: TSource, index: number, source: Enumerable<TSource>): [TKey, TValue] => [selectKey(value, index, source), selectValue(value, index, source)]
- const aggregateGroup = <TKey, TElement> (map: Map<TKey, Set<TElement>>, [key, value]: [TKey, TElement]) => {
- const set = map.get(key)
- if (set) {
- set.add(value)
- } else {
- map.set(key, new Set([value]))
- }
- return map
- }
- export class Enumerable<TSource> implements Enumerable<TSource> {
- public readonly [Symbol.iterator]: () => IterableIterator<TSource>
- private readonly compare?: CompareFunction<TSource>
- constructor (iterator: () => IterableIterator<TSource>, compare?: CompareFunction<TSource>) {
- this[Symbol.iterator] = iterator
- this.compare = compare
- }
- aggregate (this: Enumerable<TSource>, aggregate: AggregateFunction<TSource, TSource>): TSource | never
- aggregate<TAccumulate> (this: Enumerable<TSource>, aggregate: AggregateFunction<TSource, TAccumulate>, seed: TAccumulate): TAccumulate
- aggregate<TAccumulate, TResult> (this: Enumerable<TSource>, aggregate: AggregateFunction<TSource, TAccumulate>, seed: TAccumulate, select: SelectFunction<TAccumulate, TResult>): TResult
- aggregate<TAccumulate, TResult> (this: Enumerable<TSource>, aggregate: AggregateFunction<TSource, TSource> | AggregateFunction<TSource, TAccumulate>, seed?: TAccumulate, select?: SelectFunction<TAccumulate, TResult>): TSource | TAccumulate | TResult | never {
- const iterator = this[Symbol.iterator]()
- if (seed === undefined) {
- const { value, done } = iterator.next()
- if (done) {
- throw new RangeError('aggregate of empty enumerable')
- }
- return aggregateImpl(iterator, value, aggregate as AggregateFunction<TSource, TSource>, 1, this)
- }
- const result = aggregateImpl(iterator, seed, aggregate as AggregateFunction<TSource, TAccumulate>, 0, this)
- return select === undefined
- ? result
- : select(result)
- }
- aggregateRight (this: Enumerable<TSource>, aggregate: AggregateFunction<TSource, TSource>): TSource | never
- aggregateRight<TAccumulate> (this: Enumerable<TSource>, aggregate: AggregateFunction<TSource, TAccumulate>, seed: TAccumulate): TAccumulate
- aggregateRight<TAccumulate, TResult> (this: Enumerable<TSource>, aggregate: AggregateFunction<TSource, TAccumulate>, seed: TAccumulate, select: SelectFunction<TAccumulate, TResult>): TResult
- aggregateRight<TAccumulate, TResult> (this: Enumerable<TSource>, aggregate: AggregateFunction<TSource, TSource> | AggregateFunction<TSource, TAccumulate>, seed?: TAccumulate, select?: SelectFunction<TAccumulate, TResult>): TSource | TAccumulate | TResult | never {
- const array = this.toArray()
- const { length } = array
- if (seed === undefined) {
- if (length === 0) {
- throw new RangeError('aggregate of empty enumerable')
- }
- return aggregateRightImpl(array, array[length - 1], aggregate as AggregateFunction<TSource, TSource>, length - 2, this)
- }
- const result = aggregateRightImpl(array, seed, aggregate as AggregateFunction<TSource, TAccumulate>, length - 1, this)
- return select === undefined
- ? result
- : select(result)
- }
- all (this: Enumerable<TSource>, predicate: PredicateFunction<TSource>): boolean {
- if (predicate !== predicateFn) {
- let index = 0
- for (const value of this) {
- if (!predicate(value, index++, this)) {
- return false
- }
- }
- }
- return true
- }
- any (this: Enumerable<TSource>, predicate: PredicateFunction<TSource>): boolean {
- let index = 0
- for (const value of this) {
- if (predicate(value, index++, this)) {
- return true
- }
- }
- return false
- }
- append (this: Enumerable<TSource>, element: TSource): Enumerable<TSource> {
- return new Enumerable(function * (this: Enumerable<TSource>, element: TSource) {
- yield * this
- yield element
- }.bind(this, element))
- }
- asEnumerable (this: Iterable<TSource>): Enumerable<TSource> {
- return isEnumerable(this)
- ? this
- : new Enumerable(this[Symbol.iterator].bind(this))
- }
- average (this: Enumerable<number>): number | never
- average (this: Enumerable<number>, select: IndexedSelectFunction<number, number>): number | never
- average (this: Enumerable<TSource>, select: IndexedSelectFunction<TSource, number>): number | never
- average (this: Enumerable<number> | Enumerable<TSource>, select?: IndexedSelectFunction<number, number> | IndexedSelectFunction<TSource, number>): number | never {
- const average: AggregateFunction<number, number> = (accumulator, value, index) => (accumulator * index + value) / (index + 1)
- return select === undefined
- ? (this as Enumerable<number>).aggregate(average)
- : (this as Enumerable<TSource>).select(select as IndexedSelectFunction<TSource, number>).aggregate(average)
- }
- concat (this: Enumerable<TSource>, ...items: (Enumerable<TSource> | ConcatArray<TSource>)[]): Enumerable<TSource> {
- return new Enumerable(function * (this: Enumerable<TSource>, items: (Enumerable<TSource> | ConcatArray<TSource>)[]) {
- yield * this
- for (const item of items) {
- if (isEnumerable(item)) {
- yield * item
- } else {
- for (let index = 0; index < item.length; index++) {
- yield item[index]
- }
- }
- }
- }.bind(this, items))
- }
- contains (this: Enumerable<TSource>, element: TSource, equality: EqualityFunction<TSource> = equalityFn): boolean {
- if (equality === equalityFn && this instanceof Set) {
- return this.has(element)
- }
- for (const value of this) {
- if (equality(element, value)) {
- return true
- }
- }
- return false
- }
- count (this: Enumerable<TSource>, predicate: PredicateFunction<TSource> = predicateFn): number {
- if (predicate === predicateFn && Array.isArray(this)) {
- return this.length
- }
- let count = 0
- for (const _ of this.where(predicate)) {
- count++
- }
- return count
- }
- defaultIfEmpty (this: Enumerable<TSource>, element: TSource): Enumerable<TSource> {
- return new Enumerable(function * (this: Enumerable<TSource>, element: TSource) {
- const iterator = this[Symbol.iterator]()
- const { value, done } = iterator.next()
- if (done) {
- yield element
- } else {
- yield value
- yield * iterator
- }
- }.bind(this, element), this.compare)
- }
- distinct (this: Enumerable<TSource>, equality: EqualityFunction<TSource> = equalityFn): Enumerable<TSource> {
- return equality === equalityFn
- ? new Enumerable(function * (this: Enumerable<TSource>) {
- const set = new Set<TSource>()
- const unique = (value: TSource) => {
- if (set.has(value)) {
- return false
- }
- set.add(value)
- return true
- }
- yield * this.where(unique)
- }.bind(this), this.compare)
- : new Enumerable(function * (this: Enumerable<TSource>, equality: EqualityFunction<TSource>) {
- const set: TSource[] = []
- const unique = (value: TSource) => {
- if (set.contains(value, equality)) {
- return false
- }
- set.push(value)
- return true
- }
- yield * this.where(unique)
- }.bind(this, equality), this.compare)
- }
- elementAt (this: Enumerable<TSource>, index: number): TSource | never {
- let i = 0
- if (Array.isArray(this)) {
- if (this.length > index) {
- return this[index]
- }
- i = this.length
- } else {
- for (const value of this) {
- if (i++ === index) {
- return value
- }
- }
- }
- throw new RangeError(`element at ${index} of count ${i} enumerable`)
- }
- elementAtOrDefault (this: Enumerable<TSource>, index: number, element: TSource): TSource {
- if (Array.isArray(this)) {
- if (this.length > index) {
- return this[index]
- }
- } else {
- let i = 0
- for (const value of this) {
- if (i++ === index) {
- return value
- }
- }
- }
- return element
- }
- static empty<TSource> (): Enumerable<TSource> {
- return new Enumerable(generatorFn as () => IterableIterator<TSource>)
- }
- except (this: Enumerable<TSource>, second: Enumerable<TSource>, equality: EqualityFunction<TSource> = equalityFn): Enumerable<TSource> {
- return equality === equalityFn
- ? new Enumerable(function * (this: Enumerable<TSource>, second: Enumerable<TSource>) {
- const set = new Set(second)
- yield * this.where(value => !set.has(value))
- }.bind(this, second, equality), this.compare)
- : this.where(value => !second.contains(value, equality))
- }
- first (this: Enumerable<TSource>, predicate: PredicateFunction<TSource> = predicateFn): TSource | never {
- const { value, done } = this.where(predicate)[Symbol.iterator]().next()
- if (done) {
- throw new RangeError('first of empty enumerable')
- }
- return value
- }
- firstOrDefault (this: Enumerable<TSource>, element: TSource, predicate: PredicateFunction<TSource> = predicateFn): TSource {
- return this.where(predicate).defaultIfEmpty(element).first()
- }
- groupBy<TKey> (this: Enumerable<TSource>, selectKey: IndexedSelectFunction<TSource, TKey>): Enumerable<Grouping<TKey, TSource>>
- groupBy<TKey, TElement> (this: Enumerable<TSource>, selectKey: IndexedSelectFunction<TSource, TKey>, selectElement: IndexedSelectFunction<TSource, TElement>): Enumerable<Grouping<TKey, TElement>>
- groupBy<TKey, TElement, TResult> (this: Enumerable<TSource>, selectKey: IndexedSelectFunction<TSource, TKey>, selectElement: IndexedSelectFunction<TSource, TElement>, selectResult: ResultFunction<TKey, Enumerable<TElement>, TResult>): Enumerable<TResult>
- groupBy<TKey, TElement, TResult> (this: Enumerable<TSource>, selectKey: IndexedSelectFunction<TSource, TKey>, selectElement?: IndexedSelectFunction<TSource, TElement>, selectResult?: ResultFunction<TKey, Enumerable<TElement>, TResult>): Enumerable<Grouping<TKey, TSource>> | Enumerable<Grouping<TKey, TElement>> | Enumerable<TResult> {
- return new Enumerable(function * (this: Enumerable<TSource>, selectKey: IndexedSelectFunction<TSource, TKey>, selectElement?: IndexedSelectFunction<TSource, TElement>, selectResult?: ResultFunction<TKey, Enumerable<TElement>, TResult>) {
- const lookup = selectElement === undefined
- ? this.toLookup(selectKey)
- : this.toLookup(selectKey, selectElement)
- yield * selectResult === undefined
- ? (lookup as Map<TKey, Set<TSource>>).select(([key, set]) => new Grouping(set[Symbol.iterator].bind(set), this.compare, key))
- : (lookup as Map<TKey, Set<TElement>>).select(([key, set]) => selectResult(key, set))
- }.bind(this, selectKey, selectElement, selectResult)) as Enumerable<Grouping<TKey, TSource>> | Enumerable<Grouping<TKey, TElement>> | Enumerable<TResult>
- }
- groupJoin<TInner, TKey> (this: Enumerable<TSource>, inner: Enumerable<TInner>, selectOuterKey: IndexedSelectFunction<TSource, TKey>, selectInnerKey: IndexedSelectFunction<TInner, TKey>): Enumerable<Grouping<TSource, TInner>>
- groupJoin<TInner, TKey, TResult> (this: Enumerable<TSource>, inner: Enumerable<TInner>, selectOuterKey: IndexedSelectFunction<TSource, TKey>, selectInnerKey: IndexedSelectFunction<TInner, TKey>, selectResult: ResultFunction<TSource, Enumerable<TInner>, TResult>): Enumerable<TResult>
- groupJoin<TInner, TKey, TResult> (this: Enumerable<TSource>, inner: Enumerable<TInner>, selectOuterKey: IndexedSelectFunction<TSource, TKey>, selectInnerKey: IndexedSelectFunction<TInner, TKey>, selectResult?: ResultFunction<TSource, Enumerable<TInner>, TResult>): Enumerable<Grouping<TSource, TInner>> | Enumerable<TResult> {
- const outerEntries = this.select(selectEntry(selectOuterKey, selectFn as IndexedSelectFunction<TSource, TSource>))
- const innerGroups = inner.groupBy(selectInnerKey)
- const groups = outerEntries.select(
- ([outerKey, outer]) => new Grouping<TSource, TInner>(function * (innerGroups: Enumerable<Grouping<TKey, TInner>>, outerKey: TKey) {
- yield * innerGroups.firstOrDefault(
- new Grouping(generatorFn as () => IterableIterator<TInner>, outerKey),
- ({ key }) => equalityFn(key, outerKey)
- )
- }.bind(innerGroups, outerKey), outer)
- )
- return selectResult === undefined
- ? groups
- : groups.select(group => selectResult(group.key, group.asEnumerable()))
- }
- intersect (this: Enumerable<TSource>, second: Enumerable<TSource>, equality: EqualityFunction<TSource> = equalityFn): Enumerable<TSource> {
- return equality === equalityFn
- ? new Enumerable(function * (this: Enumerable<TSource>, second: Enumerable<TSource>) {
- const set = new Set(second)
- yield * this.where(value => set.has(value)).distinct()
- }.bind(this, second), this.compare)
- : this.where(value => second.contains(value, equality)).distinct(equality)
- }
- last (this: Enumerable<TSource>, predicate: PredicateFunction<TSource> = predicateFn): TSource | never {
- const { value, done } = this.where(predicate).takeLast(1)[Symbol.iterator]().next()
- if (done) {
- throw new RangeError('last of empty enumerable')
- }
- return value
- }
- lastOrDefault (this: Enumerable<TSource>, element: TSource, predicate: PredicateFunction<TSource> = predicateFn): TSource {
- return this.where(predicate).defaultIfEmpty(element).last()
- }
- max (this: Enumerable<number>): number
- max (this: Enumerable<TSource>, select: IndexedSelectFunction<TSource, number>): number
- max (this: Enumerable<number> | Enumerable<TSource>, select?: IndexedSelectFunction<TSource, number>): number {
- const max: AggregateFunction<number, number> = (acc, value) => Math.max(acc, value)
- return select === undefined
- ? (this as Enumerable<number>).aggregate(max, -Infinity)
- : (this as Enumerable<TSource>).select(select).aggregate(max, -Infinity)
- }
- min (this: Enumerable<number>): number
- min (this: Enumerable<TSource>, select: IndexedSelectFunction<TSource, number>): number
- min (this: Enumerable<number> | Enumerable<TSource>, select?: IndexedSelectFunction<TSource, number>): number {
- const min: AggregateFunction<number, number> = (acc, value) => Math.min(acc, value)
- return select === undefined
- ? (this as Enumerable<number>).aggregate(min, Infinity)
- : (this as Enumerable<TSource>).select(select).aggregate(min, Infinity)
- }
- orderBy (this: Enumerable<TSource>, compare: CompareFunction<TSource> = compareFn): OrderedEnumerable<TSource> {
- return new Enumerable<TSource>(function * (this: Enumerable<TSource>, compare: CompareFunction<TSource>) {
- yield * Array.from(this).sort(compare)
- }.bind(this, compare), compare)
- }
- orderByDescending (this: Enumerable<TSource>, compare: CompareFunction<TSource> = compareFn): OrderedEnumerable<TSource> {
- const compareDescending: CompareFunction<TSource> = (a: TSource, b: TSource) => -compare(a, b)
- return new Enumerable<TSource>(function * (this: Enumerable<TSource>, compare: CompareFunction<TSource>) {
- yield * Array.from(this).sort(compare)
- }.bind(this, compareDescending), compareDescending)
- }
- prepend (this: Enumerable<TSource>, element: TSource): Enumerable<TSource> {
- return new Enumerable(function * (this: Enumerable<TSource>, element: TSource) {
- yield element
- yield * this
- }.bind(this, element))
- }
- static range (start: number, count: number): Enumerable<number> | never {
- if (count < 0) {
- throw new RangeError('count is less than 0')
- }
- if (start + count >= Number.MAX_SAFE_INTEGER) {
- throw new RangeError('start + count is greater than or equal to Number.MAX_SAFE_INTEGER')
- }
- return new Enumerable(function * () {
- for (let index = 0; index < count; index++) {
- yield index + start
- }
- })
- }
- static repeat<TSource> (element: TSource, count: number): Enumerable<TSource> {
- return new Enumerable(function * () {
- for (let index = 0; index < count; index++) {
- yield element
- }
- })
- }
- reverse (this: Enumerable<TSource>): Enumerable<TSource> {
- return new Enumerable(function * (this: Enumerable<TSource>) {
- yield * Array.from(this).reverse()
- }.bind(this), this.compare ? (a, b) => -(this.compare as CompareFunction<TSource>)(a, b) : undefined)
- }
- select<TResult> (this: Enumerable<TSource>, select: IndexedSelectFunction<TSource, TResult>): Enumerable<TResult> {
- return new Enumerable(function * (this: Enumerable<TSource>, select: IndexedSelectFunction<TSource, TResult>) {
- let index = 0
- for (const value of this) {
- yield select(value, index++, this)
- }
- }.bind(this, select))
- }
- selectMany<TCollection> (this: Enumerable<TSource>, select: IndexedSelectManyFunction<TSource, TCollection>): Enumerable<TCollection> {
- return new Enumerable(function * (this: Enumerable<TSource>, select: IndexedSelectManyFunction<TSource, TCollection>) {
- let index = 0
- for (const value of this) {
- yield * select(value, index++, this)
- }
- }.bind(this, select))
- }
- sequenceEqual (this: Enumerable<TSource>, second: Enumerable<TSource>, equality: EqualityFunction<TSource> = equalityFn): boolean {
- const iterator1 = this[Symbol.iterator]()
- const iterator2 = second[Symbol.iterator]()
- for (let { value: value1, done: done1 } = iterator1.next(), { value: value2, done: done2 } = iterator2.next(); !done1 || !done2; { value: value1, done: done1 } = iterator1.next(), { value: value2, done: done2 } = iterator2.next()) {
- if (done1 || done2 || !equality(value1, value2)) {
- return false
- }
- }
- return true
- }
- single (this: Enumerable<TSource>, predicate: PredicateFunction<TSource> = predicateFn): TSource | never {
- const iterator = this.where(predicate)[Symbol.iterator]()
- const { value, done: empty } = iterator.next()
- const { done: unit } = iterator.next()
- if (empty || !unit) {
- throw new TypeError('single of non-unit enumerable')
- }
- return value
- }
- singleOrDefault (this: Enumerable<TSource>, element: TSource, predicate: PredicateFunction<TSource> = predicateFn): TSource | never {
- return this.where(predicate).defaultIfEmpty(element).single()
- }
- skip (this: Enumerable<TSource>, count: number): Enumerable<TSource> {
- if (Array.isArray(this)) {
- return new Enumerable(function * (this: TSource[], count: number) {
- for (let index = count; index < this.length; index++) {
- yield this[index]
- }
- }.bind(this, count))
- }
- return this.where((_, index) => index >= count)
- }
- skipLast (this: Enumerable<TSource>, count: number): Enumerable<TSource> {
- if (Array.isArray(this)) {
- return new Enumerable(function * (this: TSource[], count: number) {
- for (let index = 0; index < this.length - count; index++) {
- yield this[index]
- }
- }.bind(this, count))
- }
- return new Enumerable(function * (this: Enumerable<TSource>, count: number) {
- const queue: TSource[] = []
- for (const value of this) {
- queue.push(value)
- if (queue.length > count) {
- yield queue.shift()
- }
- }
- }.bind(this, count), this.compare)
- }
- skipWhile (this: Enumerable<TSource>, predicate: PredicateFunction<TSource>): Enumerable<TSource> {
- return new Enumerable(function * (this: Enumerable<TSource>, predicate: PredicateFunction<TSource>) {
- let condition = false
- yield * this.where((value, index, source) => condition || (condition = !predicate(value, index, source)))
- }.bind(this, predicate), this.compare)
- }
- sum (this: Enumerable<number>): number
- sum (this: Enumerable<TSource>, select: IndexedSelectFunction<TSource, number>): number
- sum (this: Enumerable<number> | Enumerable<TSource>, select?: IndexedSelectFunction<TSource, number>): number {
- const sum: AggregateFunction<number, number> = (acc, value) => acc + value
- return select === undefined
- ? (this as Enumerable<number>).aggregate(sum, 0)
- : (this as Enumerable<TSource>).select(select).aggregate(sum, 0)
- }
- take (this: Enumerable<TSource>, count: number): Enumerable<TSource> {
- return new Enumerable(function * (this: Enumerable<TSource>, count: number) {
- let index = 0
- for (const value of this) {
- if (index++ >= count) {
- return
- }
- yield value
- }
- }.bind(this, count), this.compare)
- }
- takeLast (this: Enumerable<TSource>, count: number): Enumerable<TSource> {
- if (Array.isArray(this)) {
- return new Enumerable(function * (this: TSource[], count: number) {
- for (let index = Math.max(this.length - count, 0); index < this.length; index++) {
- yield this[index]
- }
- }.bind(this, count))
- }
- return new Enumerable(function * (this: Enumerable<TSource>, count: number) {
- const queue: TSource[] = []
- for (const value of this) {
- queue.push(value)
- if (queue.length > count) {
- queue.shift()
- }
- }
- yield * queue
- }.bind(this, count), this.compare)
- }
- takeWhile (this: Enumerable<TSource>, predicate: PredicateFunction<TSource>): Enumerable<TSource> {
- return new Enumerable(function * (this: Enumerable<TSource>, predicate: PredicateFunction<TSource>) {
- let index = 0
- for (const value of this) {
- if (!predicate(value, index++, this)) {
- return
- }
- yield value
- }
- }.bind(this, predicate), this.compare)
- }
- thenBy (this: OrderedEnumerable<TSource>, compare: CompareFunction<TSource>): OrderedEnumerable<TSource> | never {
- if (this.compare === undefined) {
- throw new TypeError('thenBy of unordered enumerable')
- }
- return new Enumerable(function * (this: OrderedEnumerable<TSource>, compare: CompareFunction<TSource>) {
- const iterator = this[Symbol.iterator]()
- let { value, done } = iterator.next()
- while (!done) {
- const array: TSource[] = [value]
- for ({ value, done } = iterator.next(); !done && !(this.compare as CompareFunction<TSource>)(array[array.length - 1], value); { value, done } = iterator.next()) {
- array.push(value)
- }
- yield * array.sort(compare)
- }
- }.bind(this, this.compare, compare), (a, b) => (this.compare as CompareFunction<TSource>)(a, b) || compare(a, b))
- }
- thenByDescending (this: OrderedEnumerable<TSource>, compare: CompareFunction<TSource>): OrderedEnumerable<TSource> | never {
- if (this.compare === undefined) {
- throw new TypeError('thenBy of unordered enumerable')
- }
- const compareDescending: CompareFunction<TSource> = (a: TSource, b: TSource) => -compare(a, b)
- return new Enumerable(function * (this: OrderedEnumerable<TSource>, compare: CompareFunction<TSource>) {
- const iterator = this[Symbol.iterator]()
- let { value, done } = iterator.next()
- while (!done) {
- const array: TSource[] = [value]
- for ({ value, done } = iterator.next(); !done && !(this.compare as CompareFunction<TSource>)(array[array.length - 1], value); { value, done } = iterator.next()) {
- array.push(value)
- }
- yield * array.sort(compare)
- }
- }.bind(this, compareDescending), (a, b) => (this.compare as CompareFunction<TSource>)(a, b) || compareDescending(a, b))
- }
- toArray (this: Enumerable<TSource>): TSource[] {
- return Array.isArray(this)
- ? this
- : Array.from(this)
- }
- toMap<TKey> (this: Enumerable<TSource>, selectKey: IndexedSelectFunction<TSource, TKey>): Map<TKey, TSource>
- toMap<TKey, TValue> (this: Enumerable<TSource>, selectKey: IndexedSelectFunction<TSource, TKey>, selectValue: IndexedSelectFunction<TSource, TValue>): Map<TKey, TValue>
- toMap<TKey, TValue> (this: Enumerable<TSource>, selectKey: IndexedSelectFunction<TSource, TKey>, selectValue?: IndexedSelectFunction<TSource, TValue>): Map<TKey, TSource> | Map<TKey, TValue> {
- return selectValue === undefined
- ? new Map<TKey, TSource>(this.select(selectEntry(selectKey, selectFn as IndexedSelectFunction<TSource, TSource>)))
- : new Map<TKey, TValue>(this.select(selectEntry(selectKey, selectValue)))
- }
- toSet (this: Enumerable<TSource>): Set<TSource> {
- return this instanceof Set
- ? this
- : new Set(this)
- }
- toLookup<TKey> (this: Enumerable<TSource>, selectKey: IndexedSelectFunction<TSource, TKey>): Map<TKey, Set<TSource>>
- toLookup<TKey, TValue> (this: Enumerable<TSource>, selectKey: IndexedSelectFunction<TSource, TKey>, selectValue: IndexedSelectFunction<TSource, TValue>): Map<TKey, Set<TValue>>
- toLookup<TKey, TValue> (this: Enumerable<TSource>, selectKey: IndexedSelectFunction<TSource, TKey>, selectValue?: undefined | IndexedSelectFunction<TSource, TValue>): Map<TKey, Set<TSource>> | Map<TKey, Set<TValue>> {
- return selectValue === undefined
- ? this.select(selectEntry(selectKey, selectFn as IndexedSelectFunction<TSource, TSource>)).aggregate(aggregateGroup, new Map<TKey, Set<TSource>>()) as Map<TKey, Set<TSource>>
- : this.select(selectEntry(selectKey, selectValue)).aggregate(aggregateGroup, new Map<TKey, Set<TValue>>()) as Map<TKey, Set<TValue>>
- }
- union (this: Enumerable<TSource>, second: Enumerable<TSource>, equality: EqualityFunction<TSource> = equalityFn): Enumerable<TSource> {
- return new Enumerable<TSource>(function * (this: Enumerable<TSource>, second: Enumerable<TSource>) {
- yield * this
- yield * second
- }.bind(this, second)).distinct(equality)
- }
- where (this: Enumerable<TSource>, predicate: PredicateFunction<TSource>): Enumerable<TSource> {
- if (predicate === predicateFn) {
- return this.asEnumerable()
- }
- return new Enumerable(function * (this: Enumerable<TSource>, predicate: PredicateFunction<TSource>) {
- let index = 0
- for (const value of this) {
- if (predicate(value, index++, this)) {
- yield value
- }
- }
- }.bind(this, predicate), this.compare)
- }
- zip<TSecond> (this: Enumerable<TSource>, second: Enumerable<TSecond>): Enumerable<[TSource, TSecond]>
- zip<TSecond, TResult> (this: Enumerable<TSource>, second: Enumerable<TSecond>, result: ResultFunction<TSource, TSecond, TResult>): Enumerable<TResult>
- zip<TSecond, TResult> (this: Enumerable<TSource>, second: Enumerable<TSecond>, result: ResultFunction<TSource, TSecond, [TSource, TSecond]> | ResultFunction<TSource, TSecond, TResult> = resultFn): Enumerable<[TSource, TSecond]> | Enumerable<TResult> {
- return new Enumerable(function * (this: Enumerable<TSource>, second: Enumerable<TSecond>, result: ResultFunction<TSource, TSecond, [TSource, TSecond]> | ResultFunction<TSource, TSecond, TResult>) {
- const iterator = second[Symbol.iterator]()
- for (const value1 of this) {
- const { value: value2, done } = iterator.next()
- if (done) {
- return
- } else {
- yield result(value1, value2)
- }
- }
- }.bind(this, second, result)) as Enumerable<[TSource, TSecond]> | Enumerable<TResult>
- }
- }
- class Grouping<TKey, TSource> extends Enumerable<TSource> {
- readonly key: TKey
- constructor (iteratorFn: () => IterableIterator<TSource>, key: TKey)
- constructor (iteratorFn: () => IterableIterator<TSource>, compare: undefined | CompareFunction<TSource>, key: TKey)
- constructor (iteratorFn: () => IterableIterator<TSource>, compare: undefined | TKey | CompareFunction<TSource>, key?: TKey) {
- if (arguments.length < 3) {
- key = compare as TKey
- compare = undefined
- }
- super(iteratorFn, compare as undefined | CompareFunction<TSource>)
- this.key = key as TKey
- }
- }
Add Comment
Please, Sign In to add comment