Skip to content

Commit

Permalink
feat(array): product
Browse files Browse the repository at this point in the history
  • Loading branch information
yamcodes committed Sep 10, 2024
1 parent fda13eb commit 1832dec
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 1 deletion.
30 changes: 30 additions & 0 deletions benchmarks/array/product.bench.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import * as _ from 'radashi'

describe('product', () => {
bench('with no arguments', () => {
_.product([])
})

bench('with single empty array', () => {
_.product([[]])
})

bench('with one non-empty array (n=1)', () => {
_.product([['a', 'b', 'c']])
})

bench('with two small arrays (n=2)', () => {
_.product([
['red', 'blue'],
['fast', 'slow'],
])
})

bench('with three small arrays (n=3)', () => {
_.product([
['red', 'blue'],
['fast', 'slow'],
['big', 'small'],
])
})
})
28 changes: 28 additions & 0 deletions docs/array/product.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
title: product
description: Perform a Cartesian product of arrays
---

### Usage

Creates an array of all possible combinations (Cartesian product) from the given arrays, where each combination is represented as an array (or tuple) of elements.

```ts
import * as _ from 'radashi'

const colors = ['red', 'blue']
const sizes = ['big', 'small']
const compliments = ['nice', 'great']

_.product([colors, sizes, numbers])
// => [
// ['red', 'big', 'nice'],
// ['red', 'big', 'great'],
// ['red', 'small', 'nice'],
// ['red', 'small', 'great'],
// ['blue', 'big', 'nice'],
// ['blue', 'big', 'great'],
// ['blue', 'small', 'nice'],
// ['blue', 'small', 'great']
// ]
```
26 changes: 26 additions & 0 deletions src/array/product.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* Perform a Cartesian product of arrays, combining all elements from the
* input arrays into all possible combinations.
*
* @see https://radashi.js.org/reference/array/product
* @example
* ```ts
* product([['red', 'blue'], ['big', 'small'], ['fast', 'slow']])
* // => [['red', 'big', 'fast'], ['red', 'big', 'slow'], ['red', 'small', 'fast'], ['red', 'small', 'slow'], ['blue', 'big', 'fast'], ['blue', 'big', 'slow'], ['blue', 'small', 'fast'], ['blue', 'small', 'slow']]
* ```
*/
export function product<T>(arrays: T[][]): T[][] {
let out: T[][] = [[]]
for (const array of arrays) {
const result: T[][] = []
for (const currentArray of out) {
for (const item of array) {
const currentArrayCopy = currentArray.slice()
currentArrayCopy.push(item)
result.push(currentArrayCopy)
}
}
out = result
}
return out
}
2 changes: 1 addition & 1 deletion src/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export * from './array/list.ts'
export * from './array/mapify.ts'
export * from './array/merge.ts'
export * from './array/objectify.ts'
export * from './array/product.ts'
export * from './array/replace.ts'
export * from './array/replaceOrAppend.ts'
export * from './array/select.ts'
Expand All @@ -28,7 +29,6 @@ export * from './array/unique.ts'
export * from './array/unzip.ts'
export * from './array/zip.ts'
export * from './array/zipToObject.ts'

export * from './async/AggregateError.ts'
export * from './async/all.ts'
export * from './async/defer.ts'
Expand Down
50 changes: 50 additions & 0 deletions tests/array/product.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import * as _ from 'radashi'

describe('product', () => {
test('returns an array containing an empty array when given an empty input array (n=0)', () => {
expect(_.product([])).toEqual([[]])
})
test('returns an empty array when given an array containing an empty array (n=1)', () => {
expect(_.product([[]])).toEqual([])
})
test('returns an empty array when given multiple empty arrays (n>1)', () => {
expect(_.product([[], [], []])).toEqual([])
})
test('returns an empty array when one of the arrays in the input is empty (n>1)', () => {
expect(_.product([['1', '2', '3'], []])).toEqual([])
})
test('returns an array of singletons when given a single array (n=1)', () => {
expect(_.product([['1', '2', '3']])).toEqual([['1'], ['2'], ['3']])
})
test('performs a correct Cartesian product for two arrays (n=2)', () => {
expect(
_.product([
['red', 'blue'],
['fast', 'slow'],
]),
).toEqual([
['red', 'fast'],
['red', 'slow'],
['blue', 'fast'],
['blue', 'slow'],
])
})
test('performs a correct Cartesian product for more than two arrays (n>2)', () => {
expect(
_.product([
['red', 'blue'],
['fast', 'slow'],
['big', 'small'],
]),
).toEqual([
['red', 'fast', 'big'],
['red', 'fast', 'small'],
['red', 'slow', 'big'],
['red', 'slow', 'small'],
['blue', 'fast', 'big'],
['blue', 'fast', 'small'],
['blue', 'slow', 'big'],
['blue', 'slow', 'small'],
])
})
})

0 comments on commit 1832dec

Please sign in to comment.