ReactiveX / IxJS

The Interactive Extensions for JavaScript
https://reactivex.io/IxJS/
MIT License
1.32k stars 73 forks source link

ExtremaByAsyncIterator doesn't produce the expected result when the extremum is the first item of the source. #284

Closed millimoose closed 4 years ago

millimoose commented 4 years ago

IxJS version: 2.5.3

Code to reproduce:

import * as aix from 'ix/asynciterable';

async function *xx() {
  yield {x: 3};
  yield {x: 2};
  yield {x: 1};
}

async function main() {
  console.log('max xx', await aix.toArray(aix.maxBy(
    xx(),
    ({x}) => x
  )));
}

main().catch(console.error);

Expected behavior:

The logged output is the array `[{x: 3}]

Actual behavior:

The output is the empty array [].

Additional information:

The example code produces the expected output if yield {x: 3} is anything but the first yielded value.

millimoose commented 4 years ago

The bug seems to be around here: https://github.com/ReactiveX/IxJS/blob/7b393b4a08bec30a511b4fc9b25c21a048a6d7ce/src/asynciterable/_extremaby.ts#L39-L43

The value of current is never actually used anywhere, this should probably be:

let curr = next.value;
result.push(curr);

with the let curr declaration below just reassigning this variable instead.

millimoose commented 4 years ago

Bug remains in 3.0.0, an updated reproduction would be:

import * as aix from 'ix/asynciterable';
import * as aixop from 'ix/asynciterable/operators';

async function *xx(): any {
  yield {x: 3};
  yield {x: 2};
  yield {x: 1};
}

async function main() {
  const max = aix.from(xx()).pipe(aixop.maxBy((it: {x: number}) => it.x))
  console.warn(await aix.toArray(max))
}

main().catch(console.error);