Skip to content

Commit

Permalink
feat(reduce, reduceright): overloads that don't require seed value
Browse files Browse the repository at this point in the history
to match JS reduce
  • Loading branch information
biggyspender committed Feb 25, 2021
1 parent ab7e3a1 commit 594dd7e
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 11 deletions.
4 changes: 2 additions & 2 deletions src/helpers/headTail.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { toIterable } from './toIterable'

export const headTail = <T>(src: Iterable<T>): readonly [T, Iterable<T>] | undefined => {
export const headTail = <T>(src: Iterable<T>): readonly [T, Iterable<T>] => {
const iter = src[Symbol.iterator]()
const n = iter.next()
if (n.done) {
return undefined
throw Error('sequence is empty')
} else {
return [
n.value,
Expand Down
28 changes: 25 additions & 3 deletions src/transformers/reduce.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,34 @@
import { _aggregate } from './aggregate'
import { deferP0 } from 'ts-functional-pipe'
import { headTail } from '../helpers/headTail'

export function _reduce<T, TOut>(
src: Iterable<T>,
aggFunc: (prev: TOut, curr: T, idx: number) => TOut,
seed: TOut
) {
return _aggregate(src, seed, aggFunc)
): TOut
export function _reduce<T>(src: Iterable<T>, aggFunc: (prev: T, curr: T, idx: number) => T): T
export function _reduce<T, TOut, TT extends T | TOut>(
src: Iterable<T>,
aggFunc: (prev: TT, curr: T, idx: number) => TT,
seed?: TT
): TT {
if (typeof seed !== 'undefined') {
return _aggregate(src, seed, aggFunc)
} else {
const [head, tail] = headTail(src)
return _aggregate(tail, head as TT, aggFunc)
}
}

export const reduce = deferP0(_reduce)
export function reduce<T, TOut>(
aggFunc: (prev: TOut, curr: T, idx: number) => TOut,
seed: TOut
): (source: Iterable<T>) => TOut
export function reduce<T>(aggFunc: (prev: T, curr: T, idx: number) => T): (source: Iterable<T>) => T
export function reduce<T, TOut, TT extends T | TOut>(
aggFunc: (prev: TT, curr: T, idx: number) => TT,
seed?: TT
): (source: Iterable<T>) => TT {
return (source: Iterable<T>) => _reduce(source, aggFunc, seed as TT)
}
26 changes: 23 additions & 3 deletions src/transformers/reduceRight.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,31 @@
import { aggregate } from './aggregate'
import { deferP0, pp } from 'ts-functional-pipe'
import { reverse } from './reverse'
import { reduce } from './reduce'
export function _reduceRight<T, TOut>(
src: Iterable<T>,
aggFunc: (prev: TOut, curr: T, idx: number) => TOut,
seed: TOut
) {
return pp(src, reverse(), aggregate(seed, aggFunc))
): TOut
export function _reduceRight<T>(src: Iterable<T>, aggFunc: (prev: T, curr: T, idx: number) => T): T
export function _reduceRight<T, TOut, TT extends T | TOut>(
src: Iterable<T>,
aggFunc: (prev: TT, curr: T, idx: number) => TT,
seed?: TT
): TT {
return pp(src, reverse(), reduce(aggFunc, seed as TT))
}

export function reduceRight<T, TOut>(
aggFunc: (prev: TOut, curr: T, idx: number) => TOut,
seed: TOut
): (source: Iterable<T>) => TOut
export function reduceRight<T>(
aggFunc: (prev: T, curr: T, idx: number) => T
): (source: Iterable<T>) => T
export function reduceRight<T, TOut, TT extends T | TOut>(
aggFunc: (prev: TT, curr: T, idx: number) => TT,
seed?: TT
): (source: Iterable<T>) => TT {
return (source: Iterable<T>) => _reduceRight(source, aggFunc, seed as TT)
}
export const reduceRight = deferP0(_reduceRight)
48 changes: 45 additions & 3 deletions test/ts-iterable-functions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ import {
_select,
headTail,
_sequenceEqual,
_reduce,
toIterable,
} from '../src/ts-iterable-functions'
import { Date } from './Date'
import { deepEqualityComparer } from 'ts-equality-comparer'
Expand Down Expand Up @@ -268,6 +270,17 @@ describe('blinq test', () => {
reduce((prev, curr) => prev + curr, 0)
)
expect(v).toEqual(6)
const v2 = pp(
range(0, 4),
reduce((prev, curr) => prev + curr)
)
expect(v2).toEqual(6)
const v3 = pp(
range(0, 4),
map((v) => v.toString()),
reduce((prev, curr) => `${prev}${curr}`)
)
expect(v3).toEqual('0123')
})
it('reduceRight', () => {
const v = pp(
Expand All @@ -279,6 +292,17 @@ describe('blinq test', () => {
reduceRight((prev, curr) => prev.concat(curr), new Array<number>())
)
expect(v).toEqual([4, 5, 2, 3, 0, 1])
const v2 = pp(
range(0, 4),
reduceRight((prev, curr) => prev + curr)
)
expect(v2).toEqual(6)
const v3 = pp(
range(0, 4),
map((v) => v.toString()),
reduceRight((prev, curr) => `${prev}${curr}`)
)
expect(v3).toEqual('3210')
})
it('all', () => {
const fourZeroes = repeat(0, 4)
Expand Down Expand Up @@ -1180,11 +1204,29 @@ describe('blinq test', () => {
})
it('headTail', () => {
const h = headTail(range(0, 10))
if (h == null) {
throw Error('bad')
}
const [head, tail] = h
expect(head).toBe(0)
expect(_sequenceEqual(tail, range(1, 9))).toBe(true)
const x: number[] = []
expect(() => headTail(x)).toThrow()
const iterable = getImpureIterable()
const [h1, t1] = headTail(iterable)
expect(h1).toBe(0)
expect([...t1]).toEqual([1, 2])
})
it('impure iterable', () => {
const iterable = getImpureIterable()
expect([...iterable]).toEqual([0, 1, 2])
expect([...iterable]).toEqual([1, 2, 3])
})
})
function getImpureIterable() {
let a = 0
const iterable = toIterable(function* () {
const start = a++
for (let i = 0; i < 3; i++) {
yield start + i
}
})
return iterable
}

0 comments on commit 594dd7e

Please sign in to comment.