diff --git a/docs/modules/Map.ts.md b/docs/modules/Map.ts.md
index 03af530f9..ff53e0ef4 100644
--- a/docs/modules/Map.ts.md
+++ b/docs/modules/Map.ts.md
@@ -58,6 +58,7 @@ Added in v2.0.0
- [collect](#collect)
- [difference](#difference)
- [elem](#elem)
+ - [filterCollect](#filtercollect)
- [foldMap](#foldmap)
- [foldMapWithIndex](#foldmapwithindex)
- [intersection](#intersection)
@@ -537,6 +538,16 @@ export declare const elem: (E: Eq) => { (a: A): (m: Map) => boole
Added in v2.0.0
+## filterCollect
+
+**Signature**
+
+```ts
+export declare const filterCollect: (O: Ord) => (f: (k: K, a: A) => O.Option) => (m: Map) => B[]
+```
+
+Added in v2.12.0
+
## foldMap
**Signature**
diff --git a/docs/modules/ReadonlyMap.ts.md b/docs/modules/ReadonlyMap.ts.md
index 5b025a855..2e226b330 100644
--- a/docs/modules/ReadonlyMap.ts.md
+++ b/docs/modules/ReadonlyMap.ts.md
@@ -67,6 +67,7 @@ Added in v2.5.0
- [difference](#difference)
- [elem](#elem)
- [empty](#empty)
+ - [filterCollect](#filtercollect)
- [foldMap](#foldmap)
- [foldMapWithIndex](#foldmapwithindex)
- [intersection](#intersection)
@@ -655,6 +656,18 @@ export declare const empty: ReadonlyMap
Added in v2.5.0
+## filterCollect
+
+**Signature**
+
+```ts
+export declare function filterCollect(
+ O: Ord
+): (f: (k: K, a: A) => Option) => (m: ReadonlyMap) => ReadonlyArray
+```
+
+Added in v2.12.0
+
## foldMap
**Signature**
diff --git a/docs/modules/ReadonlyRecord.ts.md b/docs/modules/ReadonlyRecord.ts.md
index caae504fd..7dbbb67b4 100644
--- a/docs/modules/ReadonlyRecord.ts.md
+++ b/docs/modules/ReadonlyRecord.ts.md
@@ -78,6 +78,7 @@ Added in v2.5.0
- [elem](#elem)
- [empty](#empty)
- [every](#every)
+ - [filterCollect](#filtercollect)
- [filterWithIndex](#filterwithindex)
- [foldMapWithIndex](#foldmapwithindex)
- [fromFoldable](#fromfoldable)
@@ -792,6 +793,40 @@ export declare function every(predicate: Predicate): (r: ReadonlyRecord`.
+
+**Signature**
+
+```ts
+export declare function filterCollect(
+ O: Ord
+): (f: (k: K, a: A) => Option) => (r: ReadonlyRecord) => ReadonlyArray
+```
+
+**Example**
+
+```ts
+import { none, some } from 'fp-ts/Option'
+import { filterCollect } from 'fp-ts/ReadonlyRecord'
+import { Ord } from 'fp-ts/string'
+
+const x: { readonly a: string; readonly b: boolean; readonly c: number } = { a: 'c', b: false, c: 123 }
+assert.deepStrictEqual(
+ filterCollect(Ord)((key, value) => (typeof value === 'boolean' ? none : some({ key, value })))(x),
+ [
+ { key: 'a', value: 'c' },
+ { key: 'c', value: 123 },
+ ]
+)
+```
+
+Added in v2.12.0
+
## filterWithIndex
**Signature**
diff --git a/docs/modules/Record.ts.md b/docs/modules/Record.ts.md
index e492749cf..ae07c23cf 100644
--- a/docs/modules/Record.ts.md
+++ b/docs/modules/Record.ts.md
@@ -64,6 +64,7 @@ Added in v2.0.0
- [deleteAt](#deleteat)
- [elem](#elem)
- [every](#every)
+ - [filterCollect](#filtercollect)
- [filterMapWithIndex](#filtermapwithindex)
- [filterWithIndex](#filterwithindex)
- [foldMapWithIndex](#foldmapwithindex)
@@ -641,6 +642,39 @@ export declare const every: (predicate: Predicate) => (r: Record`.
+
+**Signature**
+
+```ts
+export declare const filterCollect: (
+ O: Ord
+) => (f: (k: K, a: A) => Option) => (r: Record) => B[]
+```
+
+**Example**
+
+```ts
+import { none, some } from 'fp-ts/Option'
+import { filterCollect } from 'fp-ts/Record'
+import { Ord } from 'fp-ts/string'
+
+const x: { readonly a: string; readonly b: boolean; readonly c: number } = { a: 'c', b: false, c: 123 }
+assert.deepStrictEqual(
+ filterCollect(Ord)((key, value) => (typeof value === 'boolean' ? none : some({ key, value })))(x),
+ [
+ { key: 'a', value: 'c' },
+ { key: 'c', value: 123 },
+ ]
+)
+```
+
+Added in v2.12.0
+
## filterMapWithIndex
**Signature**
diff --git a/src/Map.ts b/src/Map.ts
index 03c49cbe0..4b3b81c91 100644
--- a/src/Map.ts
+++ b/src/Map.ts
@@ -104,6 +104,13 @@ export function collect(O: Ord): (f: (k: K, a: A) => B) => (m: Map(
+ O: Ord
+) => (f: (k: K, a: A) => Option) => (m: Map) => Array = RM.filterCollect as any
+
/**
* Get a sorted `Array` of the key/value pairs contained in a `Map`.
*
diff --git a/src/ReadonlyMap.ts b/src/ReadonlyMap.ts
index f52c80a0f..0555ee648 100644
--- a/src/ReadonlyMap.ts
+++ b/src/ReadonlyMap.ts
@@ -168,6 +168,25 @@ export function collect(O: Ord): (f: (k: K, a: A) => B) => (m: Reado
}
}
+/**
+ * @since 2.12.0
+ */
+export function filterCollect(
+ O: Ord
+): (f: (k: K, a: A) => Option) => (m: ReadonlyMap) => ReadonlyArray {
+ const keysO = keys(O)
+ return (f: (k: K, a: A) => Option) => (m: ReadonlyMap): ReadonlyArray => {
+ const out: Array = []
+ for (const key of keysO(m)) {
+ const x = f(key, m.get(key)!)
+ if (_.isSome(x)) {
+ out.push(x.value)
+ }
+ }
+ return out
+ }
+}
+
/**
* Get a sorted `ReadonlyArray` of the key/value pairs contained in a `ReadonlyMap`.
*
diff --git a/src/ReadonlyRecord.ts b/src/ReadonlyRecord.ts
index ab1b663df..9fbb7b128 100644
--- a/src/ReadonlyRecord.ts
+++ b/src/ReadonlyRecord.ts
@@ -128,6 +128,41 @@ export function collect(
}
}
+/**
+ * Map a `ReadonlyRecord` into a `ReadonlyArray` passing a key/value pair to the
+ * iterating function and filtering out undesired results. The keys in the
+ * resulting record are sorted according to the passed instance of
+ * `Ord`.
+ *
+ * @example
+ * import { none, some } from 'fp-ts/Option'
+ * import { filterCollect } from 'fp-ts/ReadonlyRecord'
+ * import { Ord } from 'fp-ts/string'
+ *
+ * const x: { readonly a: string, readonly b: boolean, readonly c: number } = { a: 'c', b: false, c: 123 }
+ * assert.deepStrictEqual(
+ * filterCollect(Ord)((key, value) => typeof value === 'boolean' ? none : some({ key, value }))(x),
+ * [{ key: 'a', value: 'c' }, { key: 'c', value: 123 }]
+ * )
+ *
+ * @since 2.12.0
+ */
+export function filterCollect(
+ O: Ord
+): (f: (k: K, a: A) => Option) => (r: ReadonlyRecord) => ReadonlyArray {
+ const keysO = keys_(O)
+ return (f: (k: K, a: A) => Option) => (r: ReadonlyRecord): ReadonlyArray => {
+ const out: Array = []
+ for (const key of keysO(r)) {
+ const x = f(key, r[key])
+ if (_.isSome(x)) {
+ out.push(x.value)
+ }
+ }
+ return out
+ }
+}
+
/**
* Get a sorted `ReadonlyArray` of the key/value pairs contained in a `ReadonlyRecord`.
*
diff --git a/src/Record.ts b/src/Record.ts
index 11d481f49..7dcb8b5a6 100644
--- a/src/Record.ts
+++ b/src/Record.ts
@@ -98,6 +98,28 @@ export function collect(
}
}
+/**
+ * Map a `Record` into an `Array` passing a key/value pair to the iterating
+ * function and filtering out undesired results. The keys in the resulting
+ * record are sorted according to the passed instance of `Ord`.
+ *
+ * @example
+ * import { none, some } from 'fp-ts/Option'
+ * import { filterCollect } from 'fp-ts/Record'
+ * import { Ord } from 'fp-ts/string'
+ *
+ * const x: { readonly a: string, readonly b: boolean, readonly c: number } = { a: 'c', b: false, c: 123 }
+ * assert.deepStrictEqual(
+ * filterCollect(Ord)((key, value) => typeof value === 'boolean' ? none : some({ key, value }))(x),
+ * [{ key: 'a', value: 'c' }, { key: 'c', value: 123 }]
+ * )
+ *
+ * @since 2.12.0
+ */
+export const filterCollect: (
+ O: Ord
+) => (f: (k: K, a: A) => Option) => (r: Record) => Array = RR.filterCollect as any
+
/**
* Get a sorted `Array` of the key/value pairs contained in a `Record`.
*
diff --git a/test/Map.ts b/test/Map.ts
index fee42208d..d913786af 100644
--- a/test/Map.ts
+++ b/test/Map.ts
@@ -225,6 +225,61 @@ describe('Map', () => {
)
})
+ it('filterCollect', () => {
+ const collectO = _.filterCollect(ordUser)
+ const f = (_k: User, a: number): O.Option => (a % 2 === 0 ? O.none : O.some(a + 1))
+ U.deepStrictEqual(
+ collectO(f)(
+ new Map([
+ [{ id: 'a' }, 1],
+ [{ id: 'b' }, 2],
+ [{ id: 'c' }, 3]
+ ])
+ ),
+ [2, 4]
+ )
+ U.deepStrictEqual(
+ collectO(f)(
+ new Map([
+ [{ id: 'b' }, 2],
+ [{ id: 'a' }, 1],
+ [{ id: 'c' }, 3]
+ ])
+ ),
+ [2, 4]
+ )
+
+ const collect = _.filterCollect(ordKey)
+ const g = (k: Key, a: Value): O.Option =>
+ k.id % 2 === 0 ? O.some([k.id, a.value]) : O.none
+ U.deepStrictEqual(
+ collect(g)(
+ new Map([
+ [{ id: 1 }, { value: 1 }],
+ [{ id: 2 }, { value: 2 }],
+ [{ id: 4 }, { value: 4 }]
+ ])
+ ),
+ [
+ [4, 4],
+ [2, 2]
+ ]
+ )
+ U.deepStrictEqual(
+ collect(g)(
+ new Map([
+ [{ id: 2 }, { value: 2 }],
+ [{ id: 1 }, { value: 1 }],
+ [{ id: 4 }, { value: 4 }]
+ ])
+ ),
+ [
+ [4, 4],
+ [2, 2]
+ ]
+ )
+ })
+
it('toArray', () => {
const m1 = new Map([
[{ id: 'a' }, 1],
diff --git a/test/ReadonlyMap.ts b/test/ReadonlyMap.ts
index ea6a24388..040c13cd0 100644
--- a/test/ReadonlyMap.ts
+++ b/test/ReadonlyMap.ts
@@ -321,6 +321,61 @@ describe('ReadonlyMap', () => {
)
})
+ it('filterCollect', () => {
+ const collectO = _.filterCollect(ordUser)
+ const f = (_k: User, a: number): O.Option => (a % 2 === 0 ? O.none : O.some(a + 1))
+ U.deepStrictEqual(
+ collectO(f)(
+ new Map([
+ [{ id: 'a' }, 1],
+ [{ id: 'b' }, 2],
+ [{ id: 'c' }, 3]
+ ])
+ ),
+ [2, 4]
+ )
+ U.deepStrictEqual(
+ collectO(f)(
+ new Map([
+ [{ id: 'b' }, 2],
+ [{ id: 'a' }, 1],
+ [{ id: 'c' }, 3]
+ ])
+ ),
+ [2, 4]
+ )
+
+ const collect = _.filterCollect(ordKey)
+ const g = (k: Key, a: Value): O.Option =>
+ k.id % 2 === 0 ? O.some([k.id, a.value]) : O.none
+ U.deepStrictEqual(
+ collect(g)(
+ new Map([
+ [{ id: 1 }, { value: 1 }],
+ [{ id: 2 }, { value: 2 }],
+ [{ id: 4 }, { value: 4 }]
+ ])
+ ),
+ [
+ [4, 4],
+ [2, 2]
+ ]
+ )
+ U.deepStrictEqual(
+ collect(g)(
+ new Map([
+ [{ id: 2 }, { value: 2 }],
+ [{ id: 1 }, { value: 1 }],
+ [{ id: 4 }, { value: 4 }]
+ ])
+ ),
+ [
+ [4, 4],
+ [2, 2]
+ ]
+ )
+ })
+
it('toReadonlyArray', () => {
const m1 = new Map([
[{ id: 'a' }, 1],
diff --git a/test/ReadonlyRecord.ts b/test/ReadonlyRecord.ts
index abbe8cca5..1f329cfbe 100644
--- a/test/ReadonlyRecord.ts
+++ b/test/ReadonlyRecord.ts
@@ -31,6 +31,16 @@ describe('ReadonlyRecord', () => {
{ key: 'b', value: false }
])
})
+ it('filterCollect', () => {
+ const x: { readonly a: string; readonly b: boolean; readonly c: number } = { a: 'c', b: false, c: 123 }
+ U.deepStrictEqual(
+ _.filterCollect(S.Ord)((key, value) => (typeof value === 'boolean' ? O.none : O.some({ key, value })))(x),
+ [
+ { key: 'a', value: 'c' },
+ { key: 'c', value: 123 }
+ ]
+ )
+ })
it('map', () => {
U.deepStrictEqual(pipe({ k1: 1, k2: 2 }, _.map(U.double)), { k1: 2, k2: 4 })
diff --git a/test/Record.ts b/test/Record.ts
index 100300190..d0220323f 100644
--- a/test/Record.ts
+++ b/test/Record.ts
@@ -31,6 +31,16 @@ describe('Record', () => {
{ key: 'b', value: false }
])
})
+ it('filterCollect', () => {
+ const x = { a: 'c', b: false, c: 123 }
+ U.deepStrictEqual(
+ _.filterCollect(S.Ord)((key, value) => (typeof value === 'boolean' ? O.none : O.some({ key, value })))(x),
+ [
+ { key: 'a', value: 'c' },
+ { key: 'c', value: 123 }
+ ]
+ )
+ })
it('map', () => {
U.deepStrictEqual(pipe({ k1: 1, k2: 2 }, _.map(U.double)), { k1: 2, k2: 4 })