Order
The Order module provides a way to compare values and determine their order.
It defines an interface Order<A> which represents a single function for comparing two values of type A.
The function returns -1, 0, or 1, indicating whether the first value is less than, equal to, or greater than the second value.
Here’s the basic structure of an Order:
interface Order<A> { (first: A, second: A): -1 | 0 | 1}Using the Built-in Orders
The Order module comes with several built-in comparators for common data types:
| Order | Description |
|---|---|
string |
Used for comparing strings. |
number |
Used for comparing numbers. |
bigint |
Used for comparing big integers. |
Date |
Used for comparing Date objects. |
Example (Using Built-in Comparators)
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 > 1nSorting Arrays
You can sort arrays using these comparators. The Array module offers a sort function that sorts arrays without altering the original one.
Example (Sorting Arrays with 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' ]You can also use an Order as a comparator with JavaScript’s native Array.sort method, but keep in mind that this will modify the original array.
Example (Using Order with Native 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' ]Deriving Orders
For more complex data structures, you may need custom sorting rules. The Order module lets you derive new Order instances from existing ones with the Order.mapInput function.
Example (Creating a Custom Order for Objects)
Imagine you have a list of Person objects, and you want to sort them by their names in ascending order.
To achieve this, you can create a custom Order.
import { Order } from "effect"
// Define the Person interfaceinterface 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)The Order.mapInput function takes two arguments:
- The existing
Orderyou want to use as a base (Order.stringin this case, for comparing strings). - A function that extracts the value you want to use for sorting from your data structure (
(person: Person) => person.namein this case).
Once you have defined your custom Order, you can apply it to sort an array of Person objects:
Example (Sorting Objects Using a Custom Order)
import { Order, Array } from "effect"
11 collapsed lines
// Define the Person interfaceinterface Person { readonly name: string readonly age: number}
// Create a custom order to sort Person objects by name in ascending orderconst 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 orderconst sortedPersons = Array.sort(persons, byName)
console.log(sortedPersons)/*Output:[ { name: 'Alice', age: 25 }, { name: 'Bob', age: 30 }, { name: 'Charlie', age: 22 }]*/Combining Orders
The Order module lets you combine multiple Order instances to create complex sorting rules. This is useful when sorting by multiple properties.
Example (Sorting by Multiple Criteria)
Imagine you have a list of people, each represented by an object with a name and an age. You want to sort this list first by name and then, for individuals with the same name, by age.
import { Order, Array } from "effect"
// Define the Person interfaceinterface Person { readonly name: string readonly age: number}
// Create an Order to sort people by their names in ascending orderconst byName = Order.mapInput(Order.string, (person: Person) => person.name)
// Create an Order to sort people by their ages in ascending orderconst byAge = Order.mapInput(Order.number, (person: Person) => person.age)
// Combine orders to sort by name, then by ageconst 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 }]*/Additional Useful Functions
The Order module provides additional functions for common comparison operations, making it easier to work with ordered values.
Reversing Order
Order.reverse inverts the order of comparison. If you have an Order for ascending values, reversing it makes it descending.
Example (Reversing an 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)Comparing Values
These functions allow you to perform simple comparisons between values:
| API | Description |
|---|---|
lessThan |
Checks if one value is strictly less than another. |
greaterThan |
Checks if one value is strictly greater than another. |
lessThanOrEqualTo |
Checks if one value is less than or equal to another. |
greaterThanOrEqualTo |
Checks if one value is greater than or equal to another. |
Example (Using Comparison Functions)
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)Finding Minimum and Maximum
The Order.min and Order.max functions return the minimum or maximum value between two values, considering the order.
Example (Finding Minimum and Maximum Numbers)
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)Clamping Values
Order.clamp restricts a value within a given range. If the value is outside the range, it is adjusted to the nearest bound.
Example (Clamping Numbers to a Range)
import { Order } from "effect"
// Define a function to clamp numbers between 20 and 30const clampNumbers = Order.clamp(Order.number)({ minimum: 20, maximum: 30,})
// Value 26 is within the range [20, 30], so it remains unchangedconsole.log(clampNumbers(26))// Output: 26
// Value 10 is below the minimum bound, so it is clamped to 20console.log(clampNumbers(10))// Output: 20
// Value 40 is above the maximum bound, so it is clamped to 30console.log(clampNumbers(40))// Output: 30Checking Value Range
Order.between checks if a value falls within a specified inclusive range.
Example (Checking if Numbers Fall Within a Range)
import { Order } from "effect"
// Create a function to check if numbers are between 20 and 30const betweenNumbers = Order.between(Order.number)({ minimum: 20, maximum: 30,})
// Value 26 falls within the range [20, 30], so it returns trueconsole.log(betweenNumbers(26))// Output: true
// Value 10 is below the minimum bound, so it returns falseconsole.log(betweenNumbers(10))// Output: false
// Value 40 is above the maximum bound, so it returns falseconsole.log(betweenNumbers(40))// Output: false