Skip to content

Commit 30a4ca4

Browse files
kwonojbenlesh
authored andcommitted
fix(reduce): index will properly start at 1 if no seed is provided, to match native Array reduce behavior
- closes #2290
1 parent d4a9aac commit 30a4ca4

File tree

2 files changed

+41
-7
lines changed

2 files changed

+41
-7
lines changed

spec/operators/reduce-spec.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import {expect} from 'chai';
12
import * as Rx from '../../dist/cjs/Rx';
23
declare const {hot, cold, asDiagram, expectObservable, expectSubscriptions, type};
34

@@ -65,6 +66,34 @@ describe('Observable.prototype.reduce', () => {
6566
expectSubscriptions(e1.subscriptions).toBe(e1subs);
6667
});
6768

69+
it('should reduce with index without seed', (done: MochaDone) => {
70+
const idx = [1, 2, 3, 4, 5];
71+
72+
Observable.range(0, 6).reduce((acc, value, index) => {
73+
console.log(index);
74+
console.log(value);
75+
expect(idx.shift()).to.equal(index);
76+
return value;
77+
}).subscribe(null, null, () => {
78+
expect(idx).to.be.empty;
79+
done();
80+
});
81+
});
82+
83+
it('should reduce with index with seed', (done: MochaDone) => {
84+
const idx = [0, 1, 2, 3, 4, 5];
85+
86+
Observable.range(0, 6).reduce((acc, value, index) => {
87+
console.log(index);
88+
console.log(value);
89+
expect(idx.shift()).to.equal(index);
90+
return value;
91+
}, -1).subscribe(null, null, () => {
92+
expect(idx).to.be.empty;
93+
done();
94+
});
95+
});
96+
6897
it('should reduce with seed if source is empty', () => {
6998
const e1 = hot('--a--^-------|');
7099
const e1subs = '^ !';

src/operator/reduce.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ export function reduce<T, R>(this: Observable<T>, accumulator: (acc: R, value: T
4444
* @see {@link mergeScan}
4545
* @see {@link scan}
4646
*
47-
* @param {function(acc: R, value: T): R} accumulator The accumulator function
47+
* @param {function(acc: R, value: T, index: number): R} accumulator The accumulator function
4848
* called on each source value.
4949
* @param {R} [seed] The initial accumulation value.
5050
* @return {Observable<R>} An observable of the accumulated values.
@@ -53,7 +53,7 @@ export function reduce<T, R>(this: Observable<T>, accumulator: (acc: R, value: T
5353
* @method reduce
5454
* @owner Observable
5555
*/
56-
export function reduce<T, R>(this: Observable<T>, accumulator: (acc: R, value: T) => R, seed?: R): Observable<R> {
56+
export function reduce<T, R>(this: Observable<T>, accumulator: (acc: R, value: T, index?: number) => R, seed?: R): Observable<R> {
5757
let hasSeed = false;
5858
// providing a seed of `undefined` *should* be valid and trigger
5959
// hasSeed! so don't use `seed !== undefined` checks!
@@ -68,7 +68,7 @@ export function reduce<T, R>(this: Observable<T>, accumulator: (acc: R, value: T
6868
}
6969

7070
export class ReduceOperator<T, R> implements Operator<T, R> {
71-
constructor(private accumulator: (acc: R, value: T) => R, private seed?: R, private hasSeed: boolean = false) {}
71+
constructor(private accumulator: (acc: R, value: T, index?: number) => R, private seed?: R, private hasSeed: boolean = false) {}
7272

7373
call(subscriber: Subscriber<R>, source: any): any {
7474
return source.subscribe(new ReduceSubscriber(subscriber, this.accumulator, this.seed, this.hasSeed));
@@ -81,15 +81,20 @@ export class ReduceOperator<T, R> implements Operator<T, R> {
8181
* @extends {Ignored}
8282
*/
8383
export class ReduceSubscriber<T, R> extends Subscriber<T> {
84-
acc: T | R;
85-
hasValue: boolean = false;
84+
private index: number = 0;
85+
private acc: T | R;
86+
private hasValue: boolean = false;
8687

8788
constructor(destination: Subscriber<R>,
88-
private accumulator: (acc: R, value: T) => R,
89+
private accumulator: (acc: R, value: T, index?: number) => R,
8990
seed: R,
9091
private hasSeed: boolean) {
9192
super(destination);
9293
this.acc = seed;
94+
95+
if (!this.hasSeed) {
96+
this.index++;
97+
}
9398
}
9499

95100
protected _next(value: T) {
@@ -104,7 +109,7 @@ export class ReduceSubscriber<T, R> extends Subscriber<T> {
104109
private _tryReduce(value: T) {
105110
let result: any;
106111
try {
107-
result = this.accumulator(<R>this.acc, value);
112+
result = this.accumulator(<R>this.acc, value, this.index++);
108113
} catch (err) {
109114
this.destination.error(err);
110115
return;

0 commit comments

Comments
 (0)