Guest User

Untitled

a guest
Oct 16th, 2018
70
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 31.71 KB | None | 0 0
  1. import {
  2. AggregateFunction,
  3. CompareFunction,
  4. EqualityFunction,
  5. PredicateFunction,
  6. ResultFunction,
  7. SelectFunction,
  8. IndexedSelectFunction,
  9. IndexedSelectManyFunction,
  10. selectFn,
  11. resultFn,
  12. predicateFn,
  13. equalityFn,
  14. compareFn,
  15. generatorFn
  16. } from './util'
  17.  
  18. export interface EnumerableConstructor {
  19. new<TSource> (iterator: () => IterableIterator<TSource>): Enumerable<TSource>
  20. new<TSource> (iterator: () => IterableIterator<TSource>, compare: undefined): Enumerable<TSource>
  21. new<TSource> (iterator: () => IterableIterator<TSource>, compare: CompareFunction<TSource>): OrderedEnumerable<TSource>
  22.  
  23. new (iterator: () => IterableIterator<any>): Enumerable<any>
  24. new (iterator: () => IterableIterator<any>, compare: undefined): Enumerable<any>
  25. new (iterator: () => IterableIterator<any>, compare: CompareFunction<any>): OrderedEnumerable<any>
  26.  
  27. empty<TSource> (): Enumerable<TSource>
  28. isEnumerable<TSource> (iterable: Iterable<TSource> | ArrayLike<TSource>): iterable is Enumerable<TSource>
  29. range (start: number, count: number): Enumerable<number> | never
  30. repeat<TSource> (element: TSource, count: number): Enumerable<TSource>
  31. }
  32.  
  33. export interface GroupingConstructor extends EnumerableConstructor {
  34. new<TSource, TKey> (iterator: () => IterableIterator<TSource>, key: TKey): Grouping<TKey, TSource>
  35. new<TSource, TKey> (iterator: () => IterableIterator<TSource>, compare: undefined, key: TKey): Grouping<TSource, TKey>
  36. new<TSource, TKey> (iterator: () => IterableIterator<TSource>, compare: CompareFunction<TSource>, key: TKey): OrderedGrouping<TKey, TSource>
  37.  
  38. new<TKey> (iterator: () => IterableIterator<any>, key: TKey): Grouping<TKey, any>
  39. new<TKey> (iterator: () => IterableIterator<any>, compare: undefined, key: TKey): Grouping<TKey, any>
  40. new<TKey> (iterator: () => IterableIterator<any>, compare: CompareFunction<any>, key: TKey): OrderedGrouping<TKey, any>
  41. }
  42.  
  43. export interface OrderedEnumerable<TSource> extends Enumerable<TSource> {
  44. defaultIfEmpty (this: OrderedEnumerable<TSource>, element: TSource): OrderedEnumerable<TSource>
  45. distinct (this: OrderedEnumerable<TSource>, equality: EqualityFunction<TSource>): OrderedEnumerable<TSource>
  46. except (this: OrderedEnumerable<TSource>, second: Enumerable<TSource>, equality: EqualityFunction<TSource>): OrderedEnumerable<TSource>
  47. groupBy<TKey> (this: OrderedEnumerable<TSource>, selectKey: IndexedSelectFunction<TSource, TKey>): Enumerable<OrderedGrouping<TKey, TSource>>
  48. groupBy<TKey, TElement> (this: OrderedEnumerable<TSource>, selectKey: IndexedSelectFunction<TSource, TKey>, selectElement: IndexedSelectFunction<TSource, TElement>): Enumerable<OrderedGrouping<TKey, TElement>>
  49. intersect (this: OrderedEnumerable<TSource>, second: Enumerable<TSource>, equality?: EqualityFunction<TSource>): OrderedEnumerable<TSource>
  50. skip (this: OrderedEnumerable<TSource>, count: number): OrderedEnumerable<TSource>
  51. skipLast (this: OrderedEnumerable<TSource>, count: number): OrderedEnumerable<TSource>
  52. skipWhile (this: OrderedEnumerable<TSource>, predicate: PredicateFunction<TSource>): OrderedEnumerable<TSource>
  53. take (this: OrderedEnumerable<TSource>, count: number): OrderedEnumerable<TSource>
  54. takeLast (this: OrderedEnumerable<TSource>, count: number): OrderedEnumerable<TSource>
  55. takeWhile (this: OrderedEnumerable<TSource>, predicate: PredicateFunction<TSource>): OrderedEnumerable<TSource>
  56. where (this: OrderedEnumerable<TSource>, predicate: PredicateFunction<TSource>): OrderedEnumerable<TSource>
  57. }
  58.  
  59. export interface OrderedGrouping<TKey, TSource> extends OrderedEnumerable<TSource> {
  60. readonly key: TKey
  61. }
  62.  
  63. const isEnumerable = <TSource> (iterable: Iterable<TSource> | ConcatArray<TSource>): iterable is Enumerable<TSource> => iterable.constructor === Enumerable
  64.  
  65. const aggregateImpl = <TSource, TResult> (iterator: IterableIterator<TSource>, accumulator: TResult, aggregate: AggregateFunction<TSource, TResult>, index: number, source: Enumerable<TSource>) => {
  66. for (const value of iterator) {
  67. accumulator = aggregate(accumulator, value, index++, source)
  68. }
  69.  
  70. return accumulator
  71. }
  72.  
  73. const aggregateRightImpl = <TSource, TResult> (array: TSource[], accumulator: TResult, aggregate: AggregateFunction<TSource, TResult>, index: number, source: Enumerable<TSource>) => {
  74. while (index >= 0) {
  75. accumulator = aggregate(accumulator, array[index], index--, source)
  76. }
  77.  
  78. return accumulator
  79. }
  80.  
  81. 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)]
  82.  
  83. const aggregateGroup = <TKey, TElement> (map: Map<TKey, Set<TElement>>, [key, value]: [TKey, TElement]) => {
  84. const set = map.get(key)
  85.  
  86. if (set) {
  87. set.add(value)
  88. } else {
  89. map.set(key, new Set([value]))
  90. }
  91.  
  92. return map
  93. }
  94.  
  95. export class Enumerable<TSource> implements Enumerable<TSource> {
  96. public readonly [Symbol.iterator]: () => IterableIterator<TSource>
  97. private readonly compare?: CompareFunction<TSource>
  98.  
  99. constructor (iterator: () => IterableIterator<TSource>, compare?: CompareFunction<TSource>) {
  100. this[Symbol.iterator] = iterator
  101. this.compare = compare
  102. }
  103.  
  104. aggregate (this: Enumerable<TSource>, aggregate: AggregateFunction<TSource, TSource>): TSource | never
  105. aggregate<TAccumulate> (this: Enumerable<TSource>, aggregate: AggregateFunction<TSource, TAccumulate>, seed: TAccumulate): TAccumulate
  106. aggregate<TAccumulate, TResult> (this: Enumerable<TSource>, aggregate: AggregateFunction<TSource, TAccumulate>, seed: TAccumulate, select: SelectFunction<TAccumulate, TResult>): TResult
  107. aggregate<TAccumulate, TResult> (this: Enumerable<TSource>, aggregate: AggregateFunction<TSource, TSource> | AggregateFunction<TSource, TAccumulate>, seed?: TAccumulate, select?: SelectFunction<TAccumulate, TResult>): TSource | TAccumulate | TResult | never {
  108. const iterator = this[Symbol.iterator]()
  109.  
  110. if (seed === undefined) {
  111. const { value, done } = iterator.next()
  112.  
  113. if (done) {
  114. throw new RangeError('aggregate of empty enumerable')
  115. }
  116.  
  117. return aggregateImpl(iterator, value, aggregate as AggregateFunction<TSource, TSource>, 1, this)
  118. }
  119.  
  120. const result = aggregateImpl(iterator, seed, aggregate as AggregateFunction<TSource, TAccumulate>, 0, this)
  121.  
  122. return select === undefined
  123. ? result
  124. : select(result)
  125. }
  126.  
  127. aggregateRight (this: Enumerable<TSource>, aggregate: AggregateFunction<TSource, TSource>): TSource | never
  128. aggregateRight<TAccumulate> (this: Enumerable<TSource>, aggregate: AggregateFunction<TSource, TAccumulate>, seed: TAccumulate): TAccumulate
  129. aggregateRight<TAccumulate, TResult> (this: Enumerable<TSource>, aggregate: AggregateFunction<TSource, TAccumulate>, seed: TAccumulate, select: SelectFunction<TAccumulate, TResult>): TResult
  130. aggregateRight<TAccumulate, TResult> (this: Enumerable<TSource>, aggregate: AggregateFunction<TSource, TSource> | AggregateFunction<TSource, TAccumulate>, seed?: TAccumulate, select?: SelectFunction<TAccumulate, TResult>): TSource | TAccumulate | TResult | never {
  131. const array = this.toArray()
  132. const { length } = array
  133.  
  134. if (seed === undefined) {
  135. if (length === 0) {
  136. throw new RangeError('aggregate of empty enumerable')
  137. }
  138.  
  139. return aggregateRightImpl(array, array[length - 1], aggregate as AggregateFunction<TSource, TSource>, length - 2, this)
  140. }
  141.  
  142. const result = aggregateRightImpl(array, seed, aggregate as AggregateFunction<TSource, TAccumulate>, length - 1, this)
  143.  
  144. return select === undefined
  145. ? result
  146. : select(result)
  147. }
  148.  
  149. all (this: Enumerable<TSource>, predicate: PredicateFunction<TSource>): boolean {
  150. if (predicate !== predicateFn) {
  151. let index = 0
  152.  
  153. for (const value of this) {
  154. if (!predicate(value, index++, this)) {
  155. return false
  156. }
  157. }
  158. }
  159.  
  160. return true
  161. }
  162.  
  163. any (this: Enumerable<TSource>, predicate: PredicateFunction<TSource>): boolean {
  164. let index = 0
  165.  
  166. for (const value of this) {
  167. if (predicate(value, index++, this)) {
  168. return true
  169. }
  170. }
  171.  
  172. return false
  173. }
  174.  
  175. append (this: Enumerable<TSource>, element: TSource): Enumerable<TSource> {
  176. return new Enumerable(function * (this: Enumerable<TSource>, element: TSource) {
  177. yield * this
  178. yield element
  179. }.bind(this, element))
  180. }
  181.  
  182. asEnumerable (this: Iterable<TSource>): Enumerable<TSource> {
  183. return isEnumerable(this)
  184. ? this
  185. : new Enumerable(this[Symbol.iterator].bind(this))
  186. }
  187.  
  188. average (this: Enumerable<number>): number | never
  189. average (this: Enumerable<number>, select: IndexedSelectFunction<number, number>): number | never
  190. average (this: Enumerable<TSource>, select: IndexedSelectFunction<TSource, number>): number | never
  191. average (this: Enumerable<number> | Enumerable<TSource>, select?: IndexedSelectFunction<number, number> | IndexedSelectFunction<TSource, number>): number | never {
  192. const average: AggregateFunction<number, number> = (accumulator, value, index) => (accumulator * index + value) / (index + 1)
  193.  
  194. return select === undefined
  195. ? (this as Enumerable<number>).aggregate(average)
  196. : (this as Enumerable<TSource>).select(select as IndexedSelectFunction<TSource, number>).aggregate(average)
  197. }
  198.  
  199. concat (this: Enumerable<TSource>, ...items: (Enumerable<TSource> | ConcatArray<TSource>)[]): Enumerable<TSource> {
  200. return new Enumerable(function * (this: Enumerable<TSource>, items: (Enumerable<TSource> | ConcatArray<TSource>)[]) {
  201. yield * this
  202.  
  203. for (const item of items) {
  204. if (isEnumerable(item)) {
  205. yield * item
  206. } else {
  207. for (let index = 0; index < item.length; index++) {
  208. yield item[index]
  209. }
  210. }
  211. }
  212. }.bind(this, items))
  213. }
  214.  
  215. contains (this: Enumerable<TSource>, element: TSource, equality: EqualityFunction<TSource> = equalityFn): boolean {
  216. if (equality === equalityFn && this instanceof Set) {
  217. return this.has(element)
  218. }
  219.  
  220. for (const value of this) {
  221. if (equality(element, value)) {
  222. return true
  223. }
  224. }
  225.  
  226. return false
  227. }
  228.  
  229. count (this: Enumerable<TSource>, predicate: PredicateFunction<TSource> = predicateFn): number {
  230. if (predicate === predicateFn && Array.isArray(this)) {
  231. return this.length
  232. }
  233.  
  234. let count = 0
  235.  
  236. for (const _ of this.where(predicate)) {
  237. count++
  238. }
  239.  
  240. return count
  241. }
  242.  
  243. defaultIfEmpty (this: Enumerable<TSource>, element: TSource): Enumerable<TSource> {
  244. return new Enumerable(function * (this: Enumerable<TSource>, element: TSource) {
  245. const iterator = this[Symbol.iterator]()
  246. const { value, done } = iterator.next()
  247.  
  248. if (done) {
  249. yield element
  250. } else {
  251. yield value
  252. yield * iterator
  253. }
  254. }.bind(this, element), this.compare)
  255. }
  256.  
  257. distinct (this: Enumerable<TSource>, equality: EqualityFunction<TSource> = equalityFn): Enumerable<TSource> {
  258. return equality === equalityFn
  259. ? new Enumerable(function * (this: Enumerable<TSource>) {
  260. const set = new Set<TSource>()
  261. const unique = (value: TSource) => {
  262. if (set.has(value)) {
  263. return false
  264. }
  265.  
  266. set.add(value)
  267.  
  268. return true
  269. }
  270.  
  271. yield * this.where(unique)
  272. }.bind(this), this.compare)
  273. : new Enumerable(function * (this: Enumerable<TSource>, equality: EqualityFunction<TSource>) {
  274. const set: TSource[] = []
  275. const unique = (value: TSource) => {
  276. if (set.contains(value, equality)) {
  277. return false
  278. }
  279.  
  280. set.push(value)
  281.  
  282. return true
  283. }
  284.  
  285. yield * this.where(unique)
  286. }.bind(this, equality), this.compare)
  287. }
  288.  
  289. elementAt (this: Enumerable<TSource>, index: number): TSource | never {
  290. let i = 0
  291.  
  292. if (Array.isArray(this)) {
  293. if (this.length > index) {
  294. return this[index]
  295. }
  296.  
  297. i = this.length
  298. } else {
  299. for (const value of this) {
  300. if (i++ === index) {
  301. return value
  302. }
  303. }
  304. }
  305.  
  306. throw new RangeError(`element at ${index} of count ${i} enumerable`)
  307. }
  308.  
  309. elementAtOrDefault (this: Enumerable<TSource>, index: number, element: TSource): TSource {
  310. if (Array.isArray(this)) {
  311. if (this.length > index) {
  312. return this[index]
  313. }
  314. } else {
  315. let i = 0
  316.  
  317. for (const value of this) {
  318. if (i++ === index) {
  319. return value
  320. }
  321. }
  322. }
  323.  
  324. return element
  325. }
  326.  
  327. static empty<TSource> (): Enumerable<TSource> {
  328. return new Enumerable(generatorFn as () => IterableIterator<TSource>)
  329. }
  330.  
  331. except (this: Enumerable<TSource>, second: Enumerable<TSource>, equality: EqualityFunction<TSource> = equalityFn): Enumerable<TSource> {
  332. return equality === equalityFn
  333. ? new Enumerable(function * (this: Enumerable<TSource>, second: Enumerable<TSource>) {
  334. const set = new Set(second)
  335.  
  336. yield * this.where(value => !set.has(value))
  337. }.bind(this, second, equality), this.compare)
  338. : this.where(value => !second.contains(value, equality))
  339. }
  340.  
  341. first (this: Enumerable<TSource>, predicate: PredicateFunction<TSource> = predicateFn): TSource | never {
  342. const { value, done } = this.where(predicate)[Symbol.iterator]().next()
  343.  
  344. if (done) {
  345. throw new RangeError('first of empty enumerable')
  346. }
  347.  
  348. return value
  349. }
  350.  
  351. firstOrDefault (this: Enumerable<TSource>, element: TSource, predicate: PredicateFunction<TSource> = predicateFn): TSource {
  352. return this.where(predicate).defaultIfEmpty(element).first()
  353. }
  354.  
  355. groupBy<TKey> (this: Enumerable<TSource>, selectKey: IndexedSelectFunction<TSource, TKey>): Enumerable<Grouping<TKey, TSource>>
  356. groupBy<TKey, TElement> (this: Enumerable<TSource>, selectKey: IndexedSelectFunction<TSource, TKey>, selectElement: IndexedSelectFunction<TSource, TElement>): Enumerable<Grouping<TKey, TElement>>
  357. groupBy<TKey, TElement, TResult> (this: Enumerable<TSource>, selectKey: IndexedSelectFunction<TSource, TKey>, selectElement: IndexedSelectFunction<TSource, TElement>, selectResult: ResultFunction<TKey, Enumerable<TElement>, TResult>): Enumerable<TResult>
  358. 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> {
  359. return new Enumerable(function * (this: Enumerable<TSource>, selectKey: IndexedSelectFunction<TSource, TKey>, selectElement?: IndexedSelectFunction<TSource, TElement>, selectResult?: ResultFunction<TKey, Enumerable<TElement>, TResult>) {
  360. const lookup = selectElement === undefined
  361. ? this.toLookup(selectKey)
  362. : this.toLookup(selectKey, selectElement)
  363.  
  364. yield * selectResult === undefined
  365. ? (lookup as Map<TKey, Set<TSource>>).select(([key, set]) => new Grouping(set[Symbol.iterator].bind(set), this.compare, key))
  366. : (lookup as Map<TKey, Set<TElement>>).select(([key, set]) => selectResult(key, set))
  367. }.bind(this, selectKey, selectElement, selectResult)) as Enumerable<Grouping<TKey, TSource>> | Enumerable<Grouping<TKey, TElement>> | Enumerable<TResult>
  368. }
  369.  
  370. groupJoin<TInner, TKey> (this: Enumerable<TSource>, inner: Enumerable<TInner>, selectOuterKey: IndexedSelectFunction<TSource, TKey>, selectInnerKey: IndexedSelectFunction<TInner, TKey>): Enumerable<Grouping<TSource, TInner>>
  371. 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>
  372. 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> {
  373. const outerEntries = this.select(selectEntry(selectOuterKey, selectFn as IndexedSelectFunction<TSource, TSource>))
  374. const innerGroups = inner.groupBy(selectInnerKey)
  375. const groups = outerEntries.select(
  376. ([outerKey, outer]) => new Grouping<TSource, TInner>(function * (innerGroups: Enumerable<Grouping<TKey, TInner>>, outerKey: TKey) {
  377. yield * innerGroups.firstOrDefault(
  378. new Grouping(generatorFn as () => IterableIterator<TInner>, outerKey),
  379. ({ key }) => equalityFn(key, outerKey)
  380. )
  381. }.bind(innerGroups, outerKey), outer)
  382. )
  383.  
  384. return selectResult === undefined
  385. ? groups
  386. : groups.select(group => selectResult(group.key, group.asEnumerable()))
  387. }
  388.  
  389. intersect (this: Enumerable<TSource>, second: Enumerable<TSource>, equality: EqualityFunction<TSource> = equalityFn): Enumerable<TSource> {
  390. return equality === equalityFn
  391. ? new Enumerable(function * (this: Enumerable<TSource>, second: Enumerable<TSource>) {
  392. const set = new Set(second)
  393.  
  394. yield * this.where(value => set.has(value)).distinct()
  395. }.bind(this, second), this.compare)
  396. : this.where(value => second.contains(value, equality)).distinct(equality)
  397. }
  398.  
  399. last (this: Enumerable<TSource>, predicate: PredicateFunction<TSource> = predicateFn): TSource | never {
  400. const { value, done } = this.where(predicate).takeLast(1)[Symbol.iterator]().next()
  401.  
  402. if (done) {
  403. throw new RangeError('last of empty enumerable')
  404. }
  405.  
  406. return value
  407. }
  408.  
  409. lastOrDefault (this: Enumerable<TSource>, element: TSource, predicate: PredicateFunction<TSource> = predicateFn): TSource {
  410. return this.where(predicate).defaultIfEmpty(element).last()
  411. }
  412.  
  413. max (this: Enumerable<number>): number
  414. max (this: Enumerable<TSource>, select: IndexedSelectFunction<TSource, number>): number
  415. max (this: Enumerable<number> | Enumerable<TSource>, select?: IndexedSelectFunction<TSource, number>): number {
  416. const max: AggregateFunction<number, number> = (acc, value) => Math.max(acc, value)
  417.  
  418. return select === undefined
  419. ? (this as Enumerable<number>).aggregate(max, -Infinity)
  420. : (this as Enumerable<TSource>).select(select).aggregate(max, -Infinity)
  421. }
  422.  
  423. min (this: Enumerable<number>): number
  424. min (this: Enumerable<TSource>, select: IndexedSelectFunction<TSource, number>): number
  425. min (this: Enumerable<number> | Enumerable<TSource>, select?: IndexedSelectFunction<TSource, number>): number {
  426. const min: AggregateFunction<number, number> = (acc, value) => Math.min(acc, value)
  427.  
  428. return select === undefined
  429. ? (this as Enumerable<number>).aggregate(min, Infinity)
  430. : (this as Enumerable<TSource>).select(select).aggregate(min, Infinity)
  431. }
  432.  
  433. orderBy (this: Enumerable<TSource>, compare: CompareFunction<TSource> = compareFn): OrderedEnumerable<TSource> {
  434. return new Enumerable<TSource>(function * (this: Enumerable<TSource>, compare: CompareFunction<TSource>) {
  435. yield * Array.from(this).sort(compare)
  436. }.bind(this, compare), compare)
  437. }
  438.  
  439. orderByDescending (this: Enumerable<TSource>, compare: CompareFunction<TSource> = compareFn): OrderedEnumerable<TSource> {
  440. const compareDescending: CompareFunction<TSource> = (a: TSource, b: TSource) => -compare(a, b)
  441.  
  442. return new Enumerable<TSource>(function * (this: Enumerable<TSource>, compare: CompareFunction<TSource>) {
  443. yield * Array.from(this).sort(compare)
  444. }.bind(this, compareDescending), compareDescending)
  445. }
  446.  
  447. prepend (this: Enumerable<TSource>, element: TSource): Enumerable<TSource> {
  448. return new Enumerable(function * (this: Enumerable<TSource>, element: TSource) {
  449. yield element
  450. yield * this
  451. }.bind(this, element))
  452. }
  453.  
  454. static range (start: number, count: number): Enumerable<number> | never {
  455. if (count < 0) {
  456. throw new RangeError('count is less than 0')
  457. }
  458.  
  459. if (start + count >= Number.MAX_SAFE_INTEGER) {
  460. throw new RangeError('start + count is greater than or equal to Number.MAX_SAFE_INTEGER')
  461. }
  462.  
  463. return new Enumerable(function * () {
  464. for (let index = 0; index < count; index++) {
  465. yield index + start
  466. }
  467. })
  468. }
  469.  
  470. static repeat<TSource> (element: TSource, count: number): Enumerable<TSource> {
  471. return new Enumerable(function * () {
  472. for (let index = 0; index < count; index++) {
  473. yield element
  474. }
  475. })
  476. }
  477.  
  478. reverse (this: Enumerable<TSource>): Enumerable<TSource> {
  479. return new Enumerable(function * (this: Enumerable<TSource>) {
  480. yield * Array.from(this).reverse()
  481. }.bind(this), this.compare ? (a, b) => -(this.compare as CompareFunction<TSource>)(a, b) : undefined)
  482. }
  483.  
  484. select<TResult> (this: Enumerable<TSource>, select: IndexedSelectFunction<TSource, TResult>): Enumerable<TResult> {
  485. return new Enumerable(function * (this: Enumerable<TSource>, select: IndexedSelectFunction<TSource, TResult>) {
  486. let index = 0
  487.  
  488. for (const value of this) {
  489. yield select(value, index++, this)
  490. }
  491. }.bind(this, select))
  492. }
  493.  
  494. selectMany<TCollection> (this: Enumerable<TSource>, select: IndexedSelectManyFunction<TSource, TCollection>): Enumerable<TCollection> {
  495. return new Enumerable(function * (this: Enumerable<TSource>, select: IndexedSelectManyFunction<TSource, TCollection>) {
  496. let index = 0
  497.  
  498. for (const value of this) {
  499. yield * select(value, index++, this)
  500. }
  501. }.bind(this, select))
  502. }
  503.  
  504. sequenceEqual (this: Enumerable<TSource>, second: Enumerable<TSource>, equality: EqualityFunction<TSource> = equalityFn): boolean {
  505. const iterator1 = this[Symbol.iterator]()
  506. const iterator2 = second[Symbol.iterator]()
  507.  
  508. 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()) {
  509. if (done1 || done2 || !equality(value1, value2)) {
  510. return false
  511. }
  512. }
  513.  
  514. return true
  515. }
  516.  
  517. single (this: Enumerable<TSource>, predicate: PredicateFunction<TSource> = predicateFn): TSource | never {
  518. const iterator = this.where(predicate)[Symbol.iterator]()
  519. const { value, done: empty } = iterator.next()
  520. const { done: unit } = iterator.next()
  521.  
  522. if (empty || !unit) {
  523. throw new TypeError('single of non-unit enumerable')
  524. }
  525.  
  526. return value
  527. }
  528.  
  529. singleOrDefault (this: Enumerable<TSource>, element: TSource, predicate: PredicateFunction<TSource> = predicateFn): TSource | never {
  530. return this.where(predicate).defaultIfEmpty(element).single()
  531. }
  532.  
  533. skip (this: Enumerable<TSource>, count: number): Enumerable<TSource> {
  534. if (Array.isArray(this)) {
  535. return new Enumerable(function * (this: TSource[], count: number) {
  536. for (let index = count; index < this.length; index++) {
  537. yield this[index]
  538. }
  539. }.bind(this, count))
  540. }
  541.  
  542. return this.where((_, index) => index >= count)
  543. }
  544.  
  545. skipLast (this: Enumerable<TSource>, count: number): Enumerable<TSource> {
  546. if (Array.isArray(this)) {
  547. return new Enumerable(function * (this: TSource[], count: number) {
  548. for (let index = 0; index < this.length - count; index++) {
  549. yield this[index]
  550. }
  551. }.bind(this, count))
  552. }
  553.  
  554. return new Enumerable(function * (this: Enumerable<TSource>, count: number) {
  555. const queue: TSource[] = []
  556.  
  557. for (const value of this) {
  558. queue.push(value)
  559.  
  560. if (queue.length > count) {
  561. yield queue.shift()
  562. }
  563. }
  564. }.bind(this, count), this.compare)
  565. }
  566.  
  567. skipWhile (this: Enumerable<TSource>, predicate: PredicateFunction<TSource>): Enumerable<TSource> {
  568. return new Enumerable(function * (this: Enumerable<TSource>, predicate: PredicateFunction<TSource>) {
  569. let condition = false
  570.  
  571. yield * this.where((value, index, source) => condition || (condition = !predicate(value, index, source)))
  572. }.bind(this, predicate), this.compare)
  573. }
  574.  
  575. sum (this: Enumerable<number>): number
  576. sum (this: Enumerable<TSource>, select: IndexedSelectFunction<TSource, number>): number
  577. sum (this: Enumerable<number> | Enumerable<TSource>, select?: IndexedSelectFunction<TSource, number>): number {
  578. const sum: AggregateFunction<number, number> = (acc, value) => acc + value
  579.  
  580. return select === undefined
  581. ? (this as Enumerable<number>).aggregate(sum, 0)
  582. : (this as Enumerable<TSource>).select(select).aggregate(sum, 0)
  583. }
  584.  
  585. take (this: Enumerable<TSource>, count: number): Enumerable<TSource> {
  586. return new Enumerable(function * (this: Enumerable<TSource>, count: number) {
  587. let index = 0
  588.  
  589. for (const value of this) {
  590. if (index++ >= count) {
  591. return
  592. }
  593.  
  594. yield value
  595. }
  596. }.bind(this, count), this.compare)
  597. }
  598.  
  599. takeLast (this: Enumerable<TSource>, count: number): Enumerable<TSource> {
  600. if (Array.isArray(this)) {
  601. return new Enumerable(function * (this: TSource[], count: number) {
  602. for (let index = Math.max(this.length - count, 0); index < this.length; index++) {
  603. yield this[index]
  604. }
  605. }.bind(this, count))
  606. }
  607.  
  608. return new Enumerable(function * (this: Enumerable<TSource>, count: number) {
  609. const queue: TSource[] = []
  610.  
  611. for (const value of this) {
  612. queue.push(value)
  613.  
  614. if (queue.length > count) {
  615. queue.shift()
  616. }
  617. }
  618.  
  619. yield * queue
  620. }.bind(this, count), this.compare)
  621. }
  622.  
  623. takeWhile (this: Enumerable<TSource>, predicate: PredicateFunction<TSource>): Enumerable<TSource> {
  624. return new Enumerable(function * (this: Enumerable<TSource>, predicate: PredicateFunction<TSource>) {
  625. let index = 0
  626.  
  627. for (const value of this) {
  628. if (!predicate(value, index++, this)) {
  629. return
  630. }
  631.  
  632. yield value
  633. }
  634. }.bind(this, predicate), this.compare)
  635. }
  636.  
  637. thenBy (this: OrderedEnumerable<TSource>, compare: CompareFunction<TSource>): OrderedEnumerable<TSource> | never {
  638. if (this.compare === undefined) {
  639. throw new TypeError('thenBy of unordered enumerable')
  640. }
  641.  
  642. return new Enumerable(function * (this: OrderedEnumerable<TSource>, compare: CompareFunction<TSource>) {
  643. const iterator = this[Symbol.iterator]()
  644. let { value, done } = iterator.next()
  645.  
  646. while (!done) {
  647. const array: TSource[] = [value]
  648.  
  649. for ({ value, done } = iterator.next(); !done && !(this.compare as CompareFunction<TSource>)(array[array.length - 1], value); { value, done } = iterator.next()) {
  650. array.push(value)
  651. }
  652.  
  653. yield * array.sort(compare)
  654. }
  655. }.bind(this, this.compare, compare), (a, b) => (this.compare as CompareFunction<TSource>)(a, b) || compare(a, b))
  656. }
  657.  
  658. thenByDescending (this: OrderedEnumerable<TSource>, compare: CompareFunction<TSource>): OrderedEnumerable<TSource> | never {
  659. if (this.compare === undefined) {
  660. throw new TypeError('thenBy of unordered enumerable')
  661. }
  662.  
  663. const compareDescending: CompareFunction<TSource> = (a: TSource, b: TSource) => -compare(a, b)
  664.  
  665. return new Enumerable(function * (this: OrderedEnumerable<TSource>, compare: CompareFunction<TSource>) {
  666. const iterator = this[Symbol.iterator]()
  667. let { value, done } = iterator.next()
  668.  
  669. while (!done) {
  670. const array: TSource[] = [value]
  671.  
  672. for ({ value, done } = iterator.next(); !done && !(this.compare as CompareFunction<TSource>)(array[array.length - 1], value); { value, done } = iterator.next()) {
  673. array.push(value)
  674. }
  675.  
  676. yield * array.sort(compare)
  677. }
  678. }.bind(this, compareDescending), (a, b) => (this.compare as CompareFunction<TSource>)(a, b) || compareDescending(a, b))
  679. }
  680.  
  681. toArray (this: Enumerable<TSource>): TSource[] {
  682. return Array.isArray(this)
  683. ? this
  684. : Array.from(this)
  685. }
  686.  
  687. toMap<TKey> (this: Enumerable<TSource>, selectKey: IndexedSelectFunction<TSource, TKey>): Map<TKey, TSource>
  688. toMap<TKey, TValue> (this: Enumerable<TSource>, selectKey: IndexedSelectFunction<TSource, TKey>, selectValue: IndexedSelectFunction<TSource, TValue>): Map<TKey, TValue>
  689. toMap<TKey, TValue> (this: Enumerable<TSource>, selectKey: IndexedSelectFunction<TSource, TKey>, selectValue?: IndexedSelectFunction<TSource, TValue>): Map<TKey, TSource> | Map<TKey, TValue> {
  690. return selectValue === undefined
  691. ? new Map<TKey, TSource>(this.select(selectEntry(selectKey, selectFn as IndexedSelectFunction<TSource, TSource>)))
  692. : new Map<TKey, TValue>(this.select(selectEntry(selectKey, selectValue)))
  693. }
  694.  
  695. toSet (this: Enumerable<TSource>): Set<TSource> {
  696. return this instanceof Set
  697. ? this
  698. : new Set(this)
  699. }
  700.  
  701. toLookup<TKey> (this: Enumerable<TSource>, selectKey: IndexedSelectFunction<TSource, TKey>): Map<TKey, Set<TSource>>
  702. toLookup<TKey, TValue> (this: Enumerable<TSource>, selectKey: IndexedSelectFunction<TSource, TKey>, selectValue: IndexedSelectFunction<TSource, TValue>): Map<TKey, Set<TValue>>
  703. toLookup<TKey, TValue> (this: Enumerable<TSource>, selectKey: IndexedSelectFunction<TSource, TKey>, selectValue?: undefined | IndexedSelectFunction<TSource, TValue>): Map<TKey, Set<TSource>> | Map<TKey, Set<TValue>> {
  704. return selectValue === undefined
  705. ? this.select(selectEntry(selectKey, selectFn as IndexedSelectFunction<TSource, TSource>)).aggregate(aggregateGroup, new Map<TKey, Set<TSource>>()) as Map<TKey, Set<TSource>>
  706. : this.select(selectEntry(selectKey, selectValue)).aggregate(aggregateGroup, new Map<TKey, Set<TValue>>()) as Map<TKey, Set<TValue>>
  707. }
  708.  
  709. union (this: Enumerable<TSource>, second: Enumerable<TSource>, equality: EqualityFunction<TSource> = equalityFn): Enumerable<TSource> {
  710. return new Enumerable<TSource>(function * (this: Enumerable<TSource>, second: Enumerable<TSource>) {
  711. yield * this
  712. yield * second
  713. }.bind(this, second)).distinct(equality)
  714. }
  715.  
  716. where (this: Enumerable<TSource>, predicate: PredicateFunction<TSource>): Enumerable<TSource> {
  717. if (predicate === predicateFn) {
  718. return this.asEnumerable()
  719. }
  720.  
  721. return new Enumerable(function * (this: Enumerable<TSource>, predicate: PredicateFunction<TSource>) {
  722. let index = 0
  723.  
  724. for (const value of this) {
  725. if (predicate(value, index++, this)) {
  726. yield value
  727. }
  728. }
  729. }.bind(this, predicate), this.compare)
  730. }
  731.  
  732. zip<TSecond> (this: Enumerable<TSource>, second: Enumerable<TSecond>): Enumerable<[TSource, TSecond]>
  733. zip<TSecond, TResult> (this: Enumerable<TSource>, second: Enumerable<TSecond>, result: ResultFunction<TSource, TSecond, TResult>): Enumerable<TResult>
  734. 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> {
  735. return new Enumerable(function * (this: Enumerable<TSource>, second: Enumerable<TSecond>, result: ResultFunction<TSource, TSecond, [TSource, TSecond]> | ResultFunction<TSource, TSecond, TResult>) {
  736. const iterator = second[Symbol.iterator]()
  737.  
  738. for (const value1 of this) {
  739. const { value: value2, done } = iterator.next()
  740.  
  741. if (done) {
  742. return
  743. } else {
  744. yield result(value1, value2)
  745. }
  746. }
  747. }.bind(this, second, result)) as Enumerable<[TSource, TSecond]> | Enumerable<TResult>
  748. }
  749. }
  750.  
  751. class Grouping<TKey, TSource> extends Enumerable<TSource> {
  752. readonly key: TKey
  753.  
  754. constructor (iteratorFn: () => IterableIterator<TSource>, key: TKey)
  755. constructor (iteratorFn: () => IterableIterator<TSource>, compare: undefined | CompareFunction<TSource>, key: TKey)
  756. constructor (iteratorFn: () => IterableIterator<TSource>, compare: undefined | TKey | CompareFunction<TSource>, key?: TKey) {
  757. if (arguments.length < 3) {
  758. key = compare as TKey
  759. compare = undefined
  760. }
  761.  
  762. super(iteratorFn, compare as undefined | CompareFunction<TSource>)
  763.  
  764. this.key = key as TKey
  765. }
  766. }
Add Comment
Please, Sign In to add comment