fp-ts中按索引数组分割数组及分区操作工具咨询
在fp-ts中按外部索引数组分区后,如何便捷操作子数组?
作为fp-ts新手,你需要的是能按外部索引数组将原数组分区,并且让map、foldMap这类函数可以直接作用于分区子数组的方案。先看你的示例场景:
const x = ["a", "b", "c", "d", "e", "f"]; const p = [0, 0, 1, 2, 1, 0]; const partition = (partion: number[]) => (x: any[]) => { return x.reduce((result, nextValue, index) => { if (!(partion[index] in result)) result[partion[index]] = []; result[partion[index]].push(nextValue); return result; }, {}); }; const xPartitioned = partition(p)(x); const shout = (x: string) => x.toUpperCase() + `!`; // 当前可行的写法 const res1 = R.map(A.map(shout))(xPartitioned); // 期望的简化写法 const res2 = P.map(shout)(xPartitioned)
解决方案
fp-ts本身没有直接提供针对「键到数组」这种结构的高阶操作工具,但你可以通过两种方式实现需求:
1. 自行封装工具对象(最贴合你的预期)
直接封装你设想的P对象,还可以扩展其他需要的方法,比如foldMap:
import * as R from 'fp-ts/Record' import * as A from 'fp-ts/Array' import { Monoid } from 'fp-ts/Monoid' const P = { // 给每个子数组的元素执行map操作 map: <A, B>(fn: (a: A) => B) => (record: Record<string, A[]>) => R.map(A.map(fn))(record), // 扩展foldMap:对每个子数组执行foldMap foldMap: <M>(M: Monoid<M>) => <A>(fn: (a: A) => M) => (record: Record<string, A[]>) => R.map(A.foldMap(M)(fn))(record) }
这样就能直接用P.map(shout)(xPartitioned)得到你想要的结果。
2. 利用fp-ts的函子组合性
Record<string, _>和Array<_>都是fp-ts中的Functor,它们的组合自然也是一个Functor,你可以基于这个抽象来定义操作,本质和上面的封装逻辑一致,只是更贴合fp-ts的函数式风格。
额外优化:用fp-ts风格实现分区逻辑
你自己写的partition函数可以用fp-ts内置方法优化,利用Array.zip和Array.groupBy实现更简洁的分区:
import * as A from 'fp-ts/Array' import { pipe } from 'fp-ts/function' const x = ["a", "b", "c", "d", "e", "f"]; const p = [0, 0, 1, 2, 1, 0]; // 基于外部索引数组分组的fp-ts风格实现 const partitionByIndices = <A>(indices: number[]) => (xs: A[]) => pipe( A.zip(xs, indices), // 将元素与对应索引配对 A.groupBy(([_, idx]) => String(idx)) // 按索引字符串作为键分组 ) const xPartitioned = partitionByIndices(p)(x)
内容的提问来源于stack exchange,提问作者Adam B.
相关产品推荐
相关产品推荐

