Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add collect and collectFirst functions #327

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion cdn/radash.esm.js
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,29 @@ function shift(arr, n) {
return arr;
return [...arr.slice(-shiftNumber, arr.length), ...arr.slice(0, -shiftNumber)];
}
function collect(arr, tx) {
const res = [];
let idx = 0;
for (const el of arr) {
const transformed = tx(el, idx);
if (transformed !== void 0) {
res.push(transformed);
}
idx += 1;
}
return res;
}
function collectFirst(arr, tx) {
let idx = 0;
for (const el of arr) {
const transformed = tx(el, idx);
if (transformed !== void 0) {
return transformed;
}
idx += 1;
}
return void 0;
}

const reduce = async (array, asyncReducer, initValue) => {
const initProvided = initValue !== void 0;
Expand Down Expand Up @@ -926,4 +949,4 @@ const trim = (str, charsToTrim = " ") => {
return str.replace(regex, "");
};

export { all, alphabetical, assign, boil, callable, camel, capitalize, chain, clone, cluster, compose, construct, counting, crush, dash, debounce, defer, diff, draw, first, flat, fork, get, group, guard, intersects, invert, isArray, isDate, isEmpty, isEqual, isFloat, isFunction, isInt, isNumber, isObject, isPrimitive, isPromise, isString, isSymbol, iterate, keys, last, list, listify, lowerize, map, mapEntries, mapKeys, mapValues, max, memo, merge, min, objectify, omit, parallel, partial, partob, pascal, pick, proxied, random, range, reduce, replace, replaceOrAppend, retry, select, series, set, shake, shift, shuffle, sift, sleep, snake, sort, sum, template, throttle, title, toFloat, toInt, toggle, trim, tryit as try, tryit, uid, unique, upperize, zip, zipToObject };
export { all, alphabetical, assign, boil, callable, camel, capitalize, chain, clone, cluster, collect, collectFirst, compose, construct, counting, crush, dash, debounce, defer, diff, draw, first, flat, fork, get, group, guard, intersects, invert, isArray, isDate, isEmpty, isEqual, isFloat, isFunction, isInt, isNumber, isObject, isPrimitive, isPromise, isString, isSymbol, iterate, keys, last, list, listify, lowerize, map, mapEntries, mapKeys, mapValues, max, memo, merge, min, objectify, omit, parallel, partial, partob, pascal, pick, proxied, random, range, reduce, replace, replaceOrAppend, retry, select, series, set, shake, shift, shuffle, sift, sleep, snake, sort, sum, template, throttle, title, toFloat, toInt, toggle, trim, tryit as try, tryit, uid, unique, upperize, zip, zipToObject };
25 changes: 25 additions & 0 deletions cdn/radash.js
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,29 @@ var radash = (function (exports) {
return arr;
return [...arr.slice(-shiftNumber, arr.length), ...arr.slice(0, -shiftNumber)];
}
function collect(arr, tx) {
const res = [];
let idx = 0;
for (const el of arr) {
const transformed = tx(el, idx);
if (transformed !== void 0) {
res.push(transformed);
}
idx += 1;
}
return res;
}
function collectFirst(arr, tx) {
let idx = 0;
for (const el of arr) {
const transformed = tx(el, idx);
if (transformed !== void 0) {
return transformed;
}
idx += 1;
}
return void 0;
}

const reduce = async (array, asyncReducer, initValue) => {
const initProvided = initValue !== void 0;
Expand Down Expand Up @@ -939,6 +962,8 @@ var radash = (function (exports) {
exports.chain = chain;
exports.clone = clone;
exports.cluster = cluster;
exports.collect = collect;
exports.collectFirst = collectFirst;
exports.compose = compose;
exports.construct = construct;
exports.counting = counting;
Expand Down
2 changes: 1 addition & 1 deletion cdn/radash.min.js

Large diffs are not rendered by default.

31 changes: 31 additions & 0 deletions docs/array/collect.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
title: collect
group: 'Array'
description: Map+filter operation where undefined transformations are filtered out
---

## Basic usage

Given an array and a transform function, returns a new array
with each transformed element that does not evaluate to undefined.

```ts
import { collect } from 'radash'

const gods = [
{
name: 'Ra',
culture: 'egypt'
},
{
name: 'Zeus',
culture: 'greek'
},
{
name: 'Loki',
culture: 'greek'
}
]

collect(gods, g => (g.culture === 'greek' ? g.name.toUpperCase() : undefined)) // => ['ZEUS', 'LOKI']
```
33 changes: 33 additions & 0 deletions docs/array/collectFirst.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
title: collectFirst
group: 'Array'
description: Map+find operation where the first defined transformation is returned
---

## Basic usage

Given an array and a transform function, immediately returns the first
transformed element that does not evaluate to undefined.

```ts
import { collectFirst } from 'radash'

const gods = [
{
name: 'Ra',
culture: 'egypt'
},
{
name: 'Zeus',
culture: 'greek'
},
{
name: 'Loki',
culture: 'greek'
}
]

collectFirst(gods, g =>
g.culture === 'greek' ? g.name.toUpperCase() : undefined
) // => 'ZEUS'
```
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "radash",
"version": "11.0.0",
"version": "11.1.0",
"description": "Functional utility library - modern, simple, typed, powerful",
"main": "dist/cjs/index.cjs",
"module": "dist/esm/index.mjs",
Expand Down
47 changes: 47 additions & 0 deletions src/array.ts
Original file line number Diff line number Diff line change
Expand Up @@ -548,3 +548,50 @@ export function shift<T>(arr: Array<T>, n: number) {

return [...arr.slice(-shiftNumber, arr.length), ...arr.slice(0, -shiftNumber)]
}

/**
* A transform function for collect()/collectFirst() operations.
*/
type CollectTxFunction<T, R> = (el: T, idx: number) => R | undefined

/**
* Transform and return every element for which the tx function returns a defined value.
*
* @param arr the array of inputs to process
* @param tx the transform function
* @returns a new array containing all transformed elements which are not undefined.
*/
export function collect<T, R>(arr: T[], tx: CollectTxFunction<T, R>): R[] {
const res: R[] = []
let idx = 0
for (const el of arr) {
const transformed = tx(el, idx)
if (transformed !== undefined) {
res.push(transformed)
}
idx += 1
}
return res
}

/**
* Transform and immediately return the first element for which the tx function returns a defined value.
*
* @param arr the array of inputs to process
* @param tx the transform function
* @returns the first transformed element which is not undefined; else, undefined
*/
export function collectFirst<T, R>(
arr: T[],
tx: CollectTxFunction<T, R>
): R | undefined {
let idx = 0
for (const el of arr) {
const transformed = tx(el, idx)
if (transformed !== undefined) {
return transformed
}
idx += 1
}
return undefined
}
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ export {
alphabetical,
boil,
cluster,
collect,
collectFirst,
counting,
diff,
first,
Expand Down
56 changes: 56 additions & 0 deletions src/tests/array.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -777,4 +777,60 @@ describe('array module', () => {
assert.deepEqual(result, ['b', 'a'])
})
})

describe('collect function', () => {
test('should return all defined transformations', () => {
const arr = [{ num: 3 }, { num: -4 }, { num: -5 }]
const res = _.collect(arr, el => (el.num < 0 ? el.num * -1 : undefined))
assert.deepEqual(res, [4, 5])
})

test('should return empty list when no transformations defined', () => {
const arr = [{ num: 3 }, { num: -4 }, { num: -5 }]
const res = _.collect(arr, el => (el.num > 999 ? el.num * -1 : undefined))
assert.deepEqual(res, [])
})

test('should return falsy transformations other than undefined', () => {
const arr = [
{ val: null },
{ val: '' },
{ val: 0 },
{ val: false },
{ val: undefined }
]
const res = _.collect(arr, el => el.val)
assert.deepEqual(res, [null, '', 0, false])
})
})

describe('collectFirst function', () => {
test('should return the first defined transformation', () => {
const arr = [{ num: 3 }, { num: -4 }, { num: -5 }]
const res = _.collectFirst(arr, el =>
el.num < 0 ? el.num * -1 : undefined
)
assert.equal(res, 4)
})

test('shoudl return undefined when no transformations are defined', () => {
const arr = [{ num: 3 }, { num: -4 }, { num: -5 }]
const res = _.collectFirst(arr, el =>
el.num > 999 ? el.num * -1 : undefined
)
assert.isUndefined(res)
})

test('should return a falsy transformation other than undefined', () => {
const arr = [
{ val: undefined },
{ val: null },
{ val: '' },
{ val: 0 },
{ val: false }
]
const res = _.collectFirst(arr, el => el.val)
assert.isNull(res)
})
})
})