已发布 上游基线 bf46254 原文 ↗ 在 GitHub 编辑

Order

使用可定制的工具在 TypeScript 中比较、排序和管理值的顺序。

Order 模块提供了一种比较值并确定其顺序的方式。它定义了一个接口 Order<A>,表示用于比较两个类型为 A 的值的单个函数。该函数返回 -101,分别表示第一个值小于、等于还是大于第二个值。

Order 的基本结构如下:

interface Order<A> {
  (first: A, second: A): -1 | 0 | 1
}

使用内置的 Order

Order 模块为常见数据类型内置了若干比较器:

Order说明
string用于比较字符串。
number用于比较数字。
bigint用于比较大整数。
Date用于比较 Date 对象。

示例(使用内置比较器)

import { Order } from "effect"

console.log(Order.string("apple", "banana"))
// Output: -1, as "apple" < "banana"

console.log(Order.number(1, 1))
// Output: 0, as 1 = 1

console.log(Order.bigint(2n, 1n))
// Output: 1, as 2n > 1n

排序数组

你可以使用这些比较器对数组排序。Array 模块提供了 sort 函数,它在不修改原数组的前提下对数组排序。

示例(使用 Order 排序数组)

import { Order, Array } from "effect"

const strings = ["b", "a", "d", "c"]

const result = Array.sort(strings, Order.string)

console.log(strings) // Original array remains unchanged
// Output: [ 'b', 'a', 'd', 'c' ]

console.log(result) // Sorted array
// Output: [ 'a', 'b', 'c', 'd' ]

你也可以把 Order 用作 JavaScript 原生 Array.sort 方法的比较器,但要注意这会修改原数组。

示例(将 Order 与原生 Array.prototype.sort 一起使用)

import { Order } from "effect"

const strings = ["b", "a", "d", "c"]

strings.sort(Order.string) // Modifies the original array

console.log(strings)
// Output: [ 'a', 'b', 'c', 'd' ]

派生 Order

对于更复杂的数据结构,你可能需要自定义排序规则。Order 模块允许你通过 Order.mapInput 函数,从已有的 Order 实例派生出新的实例。

示例(为对象创建自定义 Order)

假设你有一个 Person 对象列表,想按名字升序排序。为此,你可以创建一个自定义的 Order

import { Order } from "effect"

// Define the Person interface
interface Person {
  readonly name: string
  readonly age: number
}

// Create a custom order to sort Person objects by name in ascending order
//
//      ┌─── Order<Person>
//      ▼
const byName = Order.mapInput(Order.string, (person: Person) => person.name)

Order.mapInput 函数接受两个参数:

  1. 你想用作基准的现有 Order(此处是 Order.string,用于比较字符串)。
  2. 一个从数据结构中提取排序所用值的函数(此处是 (person: Person) => person.name)。

定义好自定义 Order 之后,就可以用它来排序 Person 对象数组了:

示例(使用自定义 Order 排序对象)

import { Order, Array } from "effect"

// Define the Person interface
interface Person {
  readonly name: string
  readonly age: number
}

// Create a custom order to sort Person objects by name in ascending order
const byName = Order.mapInput(Order.string, (person: Person) => person.name)

const persons: ReadonlyArray<Person> = [
  { name: "Charlie", age: 22 },
  { name: "Alice", age: 25 },
  { name: "Bob", age: 30 },
]

// Sort persons array using the custom order
const sortedPersons = Array.sort(persons, byName)

console.log(sortedPersons)
/*
Output:
[
  { name: 'Alice', age: 25 },
  { name: 'Bob', age: 30 },
  { name: 'Charlie', age: 22 }
]
*/

组合 Order

Order 模块允许你组合多个 Order 实例,从而构造出复杂的排序规则。当需要按多个属性排序时,这非常有用。

示例(按多个条件排序)

假设你有一个人员列表,每个人用带有 nameage 的对象表示。你想先按名字排序,然后再对名字相同的人按年龄排序。

import { Order, Array } from "effect"

// Define the Person interface
interface Person {
  readonly name: string
  readonly age: number
}

// Create an Order to sort people by their names in ascending order
const byName = Order.mapInput(Order.string, (person: Person) => person.name)

// Create an Order to sort people by their ages in ascending order
const byAge = Order.mapInput(Order.number, (person: Person) => person.age)

// Combine orders to sort by name, then by age
const byNameAge = Order.combine(byName, byAge)

const result = Array.sort(
  [
    { name: "Bob", age: 20 },
    { name: "Alice", age: 18 },
    { name: "Bob", age: 18 },
  ],
  byNameAge,
)

console.log(result)
/*
Output:
[
  { name: 'Alice', age: 18 }, // Sorted by name
  { name: 'Bob', age: 18 },   // Sorted by age within the same name
  { name: 'Bob', age: 20 }
]
*/

其他实用函数

Order 模块还提供了用于常见比较操作的额外函数,让处理有序值更加容易。

反转顺序

Order.reverse 会反转比较的顺序。如果你有一个用于升序的 Order,反转它就得到降序。

示例(反转 Order)

import { Order } from "effect"

const ascendingOrder = Order.number

const descendingOrder = Order.reverse(ascendingOrder)

console.log(ascendingOrder(1, 3))
// Output: -1 (1 < 3 in ascending order)
console.log(descendingOrder(1, 3))
// Output: 1 (1 > 3 in descending order)

比较值

这些函数让你可以在值之间执行简单的比较:

API说明
lessThan检查一个值是否严格小于另一个值。
greaterThan检查一个值是否严格大于另一个值。
lessThanOrEqualTo检查一个值是否小于或等于另一个值。
greaterThanOrEqualTo检查一个值是否大于或等于另一个值。

示例(使用比较函数)

import { Order } from "effect"

console.log(Order.lessThan(Order.number)(1, 2))
// Output: true (1 < 2)

console.log(Order.greaterThan(Order.number)(5, 3))
// Output: true (5 > 3)

console.log(Order.lessThanOrEqualTo(Order.number)(2, 2))
// Output: true (2 <= 2)

console.log(Order.greaterThanOrEqualTo(Order.number)(4, 4))
// Output: true (4 >= 4)

求最小值和最大值

Order.minOrder.max 函数会根据给定的顺序,返回两个值中的最小值或最大值。

示例(求数字的最小值和最大值)

import { Order } from "effect"

console.log(Order.min(Order.number)(3, 1))
// Output: 1 (1 is the minimum)

console.log(Order.max(Order.number)(5, 8))
// Output: 8 (8 is the maximum)

将值限制在区间内

Order.clamp 会把一个值限制在给定区间内。如果该值超出区间,就会被调整到最近的边界。

示例(把数字限制在区间内)

import { Order } from "effect"

// Define a function to clamp numbers between 20 and 30
const clampNumbers = Order.clamp(Order.number)({
  minimum: 20,
  maximum: 30,
})

// Value 26 is within the range [20, 30], so it remains unchanged
console.log(clampNumbers(26))
// Output: 26

// Value 10 is below the minimum bound, so it is clamped to 20
console.log(clampNumbers(10))
// Output: 20

// Value 40 is above the maximum bound, so it is clamped to 30
console.log(clampNumbers(40))
// Output: 30

检查值的区间

Order.between 会检查一个值是否落在指定的闭区间内。

示例(检查数字是否落在区间内)

import { Order } from "effect"

// Create a function to check if numbers are between 20 and 30
const betweenNumbers = Order.between(Order.number)({
  minimum: 20,
  maximum: 30,
})

// Value 26 falls within the range [20, 30], so it returns true
console.log(betweenNumbers(26))
// Output: true

// Value 10 is below the minimum bound, so it returns false
console.log(betweenNumbers(10))
// Output: false

// Value 40 is above the maximum bound, so it returns false
console.log(betweenNumbers(40))
// Output: false