在fp-ts中如何组合2个及以上Ord实例实现多优先级排序
解决方案
你可以直接用 fp-ts/Ord 内置的组合函数 Ord.combine 拼接多个排序规则,优先级高的规则放在前面,只有当前序规则判断两个元素相等时,才会触发后续规则的判断,全程只需要做一次排序:
import { pipe } from 'fp-ts/function' import * as S from 'fp-ts/string' import * as N from 'fp-ts/number' import * as Ord from 'fp-ts/Ord' import * as A from 'fp-ts/Array' const ordStringLength = pipe(N.Ord, Ord.contramap((s: string) => s.length)) const ordString = S.Ord // 组合规则:优先按长度排序,长度相同按字母序排序 const combinedOrd = pipe( ordStringLength, Ord.combine(ordString) ) // 单次调用完成排序 const sorted = pipe(listOfStrings, A.sort(combinedOrd))
你之前连续两次调用A.sort的写法不仅有额外的O(n log n)性能开销,依赖排序稳定性的实现也可能在部分场景下得到不符合预期的结果,用组合Ord的方式可以完全规避这两个问题。
多规则扩展
如果你需要组合更多排序规则,只需要按优先级顺序往后拼接 Ord.combine 即可,比如要实现「先按长度升序、长度相同按首字母降序、首字母相同按全量字符串升序」的逻辑,只需要把对应规则按优先级顺序组合:
// 示例:额外定义按首字母降序的规则 const ordByFirstCharDesc = pipe( S.Ord, Ord.contramap((s: string) => s[0] ?? ''), Ord.reverse ) const combinedOrd = pipe( ordStringLength, // 第一优先级 Ord.combine(ordByFirstCharDesc), // 第二优先级 Ord.combine(ordString) // 第三优先级 )
补充说明
Ord.combine 的底层逻辑就是合并两个比较规则,没有额外的性能开销,时间复杂度和单次排序完全一致。如果你需要调整某条规则的排序方向,用 Ord.reverse(对应Ord实例) 包裹即可。
内容的提问来源于stack exchange,提问作者harryg
相关产品推荐
相关产品推荐

