From fa0377f72e55a83eb1779cb2098e39a216a07526 Mon Sep 17 00:00:00 2001 From: Omry Nachman Date: Wed, 19 Jul 2023 22:46:20 +0300 Subject: [PATCH] chore: updated iterables --- packages/common/src/chain.ts | 4 ++++ packages/common/src/iterables-gen.ts | 5 +++++ packages/common/src/iterables.ts | 3 +-- packages/common/src/test/chain.unit.ts | 13 ++++++++++++- packages/common/src/test/iterables.unit.ts | 17 +++++++++++++++-- 5 files changed, 37 insertions(+), 5 deletions(-) create mode 100644 packages/common/src/iterables-gen.ts diff --git a/packages/common/src/chain.ts b/packages/common/src/chain.ts index 16d646e3..d823ea1f 100644 --- a/packages/common/src/chain.ts +++ b/packages/common/src/chain.ts @@ -123,6 +123,9 @@ function chainIter(iterable: Iterable): IterableChain { return { value: iterable, iterable, + get array() { + return [...iterable]; + }, ...boundToIter, ...boundToElm, forEach: (mapping: Mapping) => { @@ -168,4 +171,5 @@ export type Chain = { skip: (count: number) => IterableChain; reduce: (reducer: (acc: A, item: T) => A, initial: A) => ValueChain; iterable: Iterable; + get array(): T[]; }; diff --git a/packages/common/src/iterables-gen.ts b/packages/common/src/iterables-gen.ts new file mode 100644 index 00000000..d0ce7a92 --- /dev/null +++ b/packages/common/src/iterables-gen.ts @@ -0,0 +1,5 @@ +export function* times(count: number, start = 0, step = 1) { + for (let i = start; i < count; i += step) { + yield i; + } +} diff --git a/packages/common/src/iterables.ts b/packages/common/src/iterables.ts index 195011a6..492698c5 100644 --- a/packages/common/src/iterables.ts +++ b/packages/common/src/iterables.ts @@ -58,8 +58,7 @@ export function size(iterable: Nullable>): number { export function at(iterable: Nullable>, index: number): T | undefined { if (iterable) { if (index < 0) { - const iterAsArray = Array.from(iterable); - return iterAsArray[iterAsArray.length + index]; + return Array.from(iterable).at(index); } let i = 0; for (const v of iterable) { diff --git a/packages/common/src/test/chain.unit.ts b/packages/common/src/test/chain.unit.ts index 3c69c52c..13088e1b 100644 --- a/packages/common/src/test/chain.unit.ts +++ b/packages/common/src/test/chain.unit.ts @@ -2,11 +2,12 @@ import { expect } from 'chai'; import { chain } from '../chain'; // @ts-expect-error no types import gc from 'expose-gc/function'; +import { times } from '../iterables-gen'; const forceGc = gc as () => void; const timer = typeof performance !== 'undefined' ? performance : Date; -describe('performance', () => { +describe('chain', () => { it('it faster than the array equivalent function for large iterables', () => { const veryLargeArray = Array.from(new Array(2 ** 18)).map((_, i) => i % 2 ** 32); forceGc(); @@ -40,4 +41,14 @@ describe('performance', () => { expect([...result]).to.eql([...iterResult]); expect(iterTime).to.be.lessThan(arrayTime); }); + + it('can chain all of the iterable functions', () => { + expect( + chain(times(10)) + .skip(2) + .map((i) => [i, 2 * i]) + .flatMap((i) => i) + .filter((i) => i < 10).array + ).to.eql([2, 4, 3, 6, 4, 8, 5, 6, 7, 8, 9]); + }); }); diff --git a/packages/common/src/test/iterables.unit.ts b/packages/common/src/test/iterables.unit.ts index 8ea59d3f..b6649c53 100644 --- a/packages/common/src/test/iterables.unit.ts +++ b/packages/common/src/test/iterables.unit.ts @@ -102,8 +102,21 @@ describe('iterables', () => { expect(isEmpty([1])).to.eql(false); }); it(`size`, () => { - expect(size([])).to.eql(0); - expect(size([0, 1])).to.eql(2); + expect(size([]), 'size of empty array').to.eql(0); + expect(size([0, 1]), 'size of array').to.eql(2); + expect(size(undefined), 'size of undefined').to.eql(0); + expect(size(null), 'size of null').to.eql(0); + expect(size(''), 'size of empty string').to.eql(0); + expect(size('hello'), 'size of string string').to.eql(5); + expect( + size( + (function* () { + yield 1; + yield 1; + })() + ), + 'generated iterator' + ).to.eql(2); }); it(`map`, () => { expect([...map([0, 1, 2], (i) => i ** 2)]).to.eql([0, 1, 4]);