From b33cf93a8b4c870051a8adf1bbb7fb4ead4f101f Mon Sep 17 00:00:00 2001 From: mb Date: Wed, 13 Dec 2023 21:08:10 +0100 Subject: [PATCH] add zipWith and pairwiseWith --- .../pages/en/array/operator/pairwiseWith.md | 49 +++++++++++++++++++ docs/src/pages/en/array/operator/zipWith.md | 41 ++++++++++++++++ package.json | 2 +- spec/core/array.spec.ts | 4 +- spec/core/array/operator/pairwiseWith.spec.ts | 18 +++++++ spec/core/array/operator/zipWith.spec.ts | 27 ++++++++++ src/array/operator/index.ts | 2 + src/array/operator/pairwiseWith.ts | 9 ++++ src/array/operator/zipWith.ts | 12 +++++ 9 files changed, 161 insertions(+), 3 deletions(-) create mode 100644 docs/src/pages/en/array/operator/pairwiseWith.md create mode 100644 docs/src/pages/en/array/operator/zipWith.md create mode 100644 spec/core/array/operator/pairwiseWith.spec.ts create mode 100644 spec/core/array/operator/zipWith.spec.ts create mode 100644 src/array/operator/pairwiseWith.ts create mode 100644 src/array/operator/zipWith.ts diff --git a/docs/src/pages/en/array/operator/pairwiseWith.md b/docs/src/pages/en/array/operator/pairwiseWith.md new file mode 100644 index 0000000..32c153b --- /dev/null +++ b/docs/src/pages/en/array/operator/pairwiseWith.md @@ -0,0 +1,49 @@ +--- +title: pairwiseWith +description: pairwiseWith +layout: ../../../../layouts/MainLayout.astro +--- +Creates elements by combining adjacent elements in an array. + +## Parameters + +`fn` (Reduction): A reduction function that takes two elements of the array and returns a single value. + +`array` (Array): An array of elements for which pairs of adjacent elements are to be created. + +## Returns + +A new array containing the result of applying the reduction function to pairs of adjacent elements. + +## Example + +```ts +import { pairwiseWith } from './pairwiseWith'; + +const inputArray = [1, 2, 3, 4, 5]; +const sumReducer = (a, b) => a + b; + +const resultArray = pairwiseWith(sumReducer)(inputArray); +// resultArray will be [3, 5, 7, 9] +``` + +## Notes + +- The `pairwiseWith` function applies the provided reduction function to pairs of adjacent elements in the input array. + +- The input array remains unaltered, and a new array is returned. + +- If the input array has less than two elements, an empty array is returned since there are no adjacent elements to pair. + +- The reduction function should take two arguments and return a value. + +- This function does not modify the original array. + + + +## See Also + +- [map](./map) +- [reduce](./reduce) +- [pairwise](./pairwise) +- [zipWith](./zipWith) diff --git a/docs/src/pages/en/array/operator/zipWith.md b/docs/src/pages/en/array/operator/zipWith.md new file mode 100644 index 0000000..989221e --- /dev/null +++ b/docs/src/pages/en/array/operator/zipWith.md @@ -0,0 +1,41 @@ +--- +title: zipWith +description: zipWith +layout: ../../../../layouts/MainLayout.astro +--- +Combines two arrays element-wise using a specified binary function. + +## Signature + +```ts +type zipWith = (mapper: BinaryFunction) => (arr1: E[]) => (arr2: F[]) => Array +``` + +## Parameters + +`mapper` (BinaryFunction): A binary function that takes elements from both arrays and returns a value. + +`arr1` (Array): The first array to be zipped. + +`arr2` (Array): The second array to be zipped. + +## Returns + +A new array containing the result of applying the `mapper` function to pairs of elements from `arr1` and `arr2`. + +```ts +import { zipWith } from './zipWith'; + +const array1 = [1, 2, 3]; +const array2 = ['a', 'b', 'c']; +const combineElements = (a, b) => `${a}-${b}`; + +const resultArray = zipWith(combineElements)(array1)(array2); +// resultArray will be ['1-a', '2-b', '3-c'] +``` + +## See Also +- [map](./map) +- [reduce](./reduce) +- [zip](./zip) +- [pairwiseWith](./pairwiseWith) diff --git a/package.json b/package.json index 05c93ab..7b4214d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fnxt", - "version": "1.18.0", + "version": "1.19.0", "description": "Functional Extensions for modern JavaScript", "main": "./dist/cjs/index.js", "module": "./dist/esm5/index.js", diff --git a/spec/core/array.spec.ts b/spec/core/array.spec.ts index af83dae..3da1e3c 100644 --- a/spec/core/array.spec.ts +++ b/spec/core/array.spec.ts @@ -24,7 +24,7 @@ describe('array', () => { 'init', 'insertAt', 'interleave', 'isEmpty', 'iter', 'last', 'length', 'map', 'maxBy', 'minBy', - 'pairwise', 'partition', 'push', + 'pairwise','pairwiseWith', 'partition', 'push', 'reduce', 'reduceBack', 'replicate', 'rev', 'rotate', 'rotateBack', 'scan', 'scanBack', 'skip', @@ -39,7 +39,7 @@ describe('array', () => { 'tryFindIndex', 'tryFindIndexBack', 'tryHead', 'tryLast', 'uniqueBy', 'updateAt', 'where', 'windowed', 'zip', - 'zip3' + 'zip3', 'zipWith' ] .sort(); operators.map(name => './array/operator/' + name + '.spec') diff --git a/spec/core/array/operator/pairwiseWith.spec.ts b/spec/core/array/operator/pairwiseWith.spec.ts new file mode 100644 index 0000000..c00ccd7 --- /dev/null +++ b/spec/core/array/operator/pairwiseWith.spec.ts @@ -0,0 +1,18 @@ +import {expect} from 'chai'; +import {pairwiseWith} from '../../../../src/array'; +import {checkThrow} from '../../../support/checkThrow'; + +describe('pairwiseWith', () => { + it('should pairwiseWith', () => { + const pairwiseSum = pairwiseWith((a:number, b:number) => a + b); + expect(pairwiseSum([1, 2, 3, 4])).to.eql([3, 5, 7]); + expect(pairwiseSum([1,2])).to.eql([3]); + expect(pairwiseSum([1])).to.eql([]); + expect(pairwiseSum([])).to.eql([]); + }); + + + it('should throw if null or undefined', () => { + checkThrow(pairwiseWith((a, b) => a + b)); + }); +}); diff --git a/spec/core/array/operator/zipWith.spec.ts b/spec/core/array/operator/zipWith.spec.ts new file mode 100644 index 0000000..a2931fc --- /dev/null +++ b/spec/core/array/operator/zipWith.spec.ts @@ -0,0 +1,27 @@ +import {expect} from 'chai'; +import {checkThrow} from '../../../support/checkThrow'; +import {zipWith} from '../../../../src/array'; + +describe('zipWith', () => { + + + it('should zipWith', () => { + const fn = zipWith((a: number, b: number) => a + b)([1, 2, 3]); + expect(fn([4, 5, 6])).to.eql([5, 7, 9],); + }); + + it('should zipWith empty', () => { + const fn = zipWith((a: number, b: number) => a + b)([]); + expect(fn([])).to.eql([]); + }); + it('should not zipWith if not same size', () => { + const fn = zipWith((a: number, b: number) => a + b)([1, 2]); + expect(() => fn([2])).to.throw(); + }); + + + it('should throw if null or undefined', () => { + const fn = zipWith((a: number, b: number) => a + b)([1]); + checkThrow(fn); + }); +}); diff --git a/src/array/operator/index.ts b/src/array/operator/index.ts index c268a9c..581f02d 100644 --- a/src/array/operator/index.ts +++ b/src/array/operator/index.ts @@ -37,6 +37,7 @@ export * from './map'; export * from './maxBy'; export * from './minBy'; export * from './pairwise'; +export * from './pairwiseWith'; export * from './partition'; export * from './push'; export * from './reduce'; @@ -83,3 +84,4 @@ export * from './where'; export * from './windowed'; export * from './zip'; export * from './zip3'; +export * from './zipWith'; diff --git a/src/array/operator/pairwiseWith.ts b/src/array/operator/pairwiseWith.ts new file mode 100644 index 0000000..57b34df --- /dev/null +++ b/src/array/operator/pairwiseWith.ts @@ -0,0 +1,9 @@ +import {Reduction} from 'fnxt/fnxt-types'; + +export const pairwiseWith = (fn: Reduction) => (array: E[]): E[] => { + const result: E[] = []; + for (let i = 1; i < array.length; i++) { + result.push(fn(array[i - 1], array[i])); + } + return result; +}; diff --git a/src/array/operator/zipWith.ts b/src/array/operator/zipWith.ts new file mode 100644 index 0000000..e4ee1af --- /dev/null +++ b/src/array/operator/zipWith.ts @@ -0,0 +1,12 @@ +import {BinaryFunction} from 'fnxt/fnxt-types'; + +export const zipWith = (mapper: BinaryFunction) => (arr1: E[]) => (arr2: F[]): Array => { + if (arr1.length !== arr2.length) { + throw new Error('Input arrays must have equal lengths'); + } + const result: Array = []; + for (let i = 0; i < arr1.length; i++) { + result.push(mapper(arr1[i], arr2[i])); + } + return result; +};