F# 集合
最后修改日期:2025 年 5 月 17 日
本文将探讨 F# 中的集合。集合是函数式编程中的一种基本数据结构,提供了一种存储唯一元素和执行集合运算的方法。
F# 中的集合是不可变的集合,不包含重复元素。它们提供高效的查找操作,并支持常见的集合操作,如并集、交集和差集。F# 集合实现为不可变平衡二叉树,这使其在函数式编程模式下非常高效。
由于 F# 中的集合是不可变的,任何修改集合的操作(如添加或删除元素)都会返回一个新的集合,而不是更改原始集合。这确保了数据的完整性,并允许安全的并发编程。此外,底层的平衡树结构确保了集合操作(如成员资格测试和迭代)即使在处理大型数据集时也能保持高性能。
创建集合
有几种方法可以在 F# 中创建集合。你可以从序列、列表、数组创建它们,或者使用集合推导式。Set
模块提供了用于处理集合的函数。
// Creating empty set let emptySet = Set.empty printfn "Empty set: %A" emptySet // Using set literal let uniqeueVals = set [ 1; 2; 3; 4; 5 ] printfn "Unique values: %A" uniqeueVals // Creating set from list let numbers = Set.ofList [ 1; 2; 3; 2; 1 ] printfn "From list: %A" numbers // Creating set from array let colors = Set.ofArray [| "red" "green" "blue" "green" |] printfn "From array: %A" colors // Helper function to check if a number is prime let isPrime n = if n < 2 then false else seq { 2 .. int (sqrt (float n)) } |> Seq.forall (fun x -> n % x <> 0) // Creating set from sequence let primes = Set.ofSeq ( seq { for i in 1..10 do if isPrime i then yield i } ) printfn "Primes: %A" primes // Set comprehension let squares = Set.ofSeq (seq { for x in 1..5 -> x * x }) printfn "Squares: %A" squares
此示例演示了创建集合的不同方法。请注意重复元素是如何自动删除的。Set.empty
函数创建一个空集合。set
函数从列表创建集合,而 ofSeq
函数允许你从任何序列(包括数组和列表)创建集合。isPrime
函数是检查数字是否为素数的辅助函数。
λ dotnet fsi creating_sets.fsx Empty set: set [] Unique values: set [1; 2; 3; 4; 5] From list: set [1; 2; 3] From array: set ["blue"; "green"; "red"] Primes: set [2; 3; 5; 7] Squares: set [1; 4; 9; 16; 25]
基本集合操作
F# 集合支持基本操作,如添加元素、检查成员资格和计算元素数量。由于集合是不可变的,修改集合的操作会返回一个新的集合,而不是更改原始集合。
let mySet = set [1; 2; 3; 4; 5] // Adding elements let biggerSet = mySet.Add(6).Add(7) printfn "After adding: %A" biggerSet // Removing elements let smallerSet = mySet.Remove(5).Remove(1) printfn "After removing: %A" smallerSet // Checking membership printfn "Contains 3? %b" (mySet.Contains 3) printfn "Contains 8? %b" (mySet.Contains 8) // Counting elements printfn "Count: %d" mySet.Count // Minimum and maximum printfn "Min: %d" (Set.minElement mySet) printfn "Max: %d" (Set.maxElement mySet)
此代码展示了基本集合操作。Add
和 Remove
返回新的集合。Contains
检查成员资格,Count
返回元素数量。minElement
和 maxElement
返回最小和最大的元素。
λ dotnet fsi basic_operations.fsx After adding: set [1; 2; 3; 4; 5; 6; 7] After removing: set [2; 3; 4] Contains 3? true Contains 8? false Count: 5 Min: 1 Max: 5
集合操作:并集、交集、差集
F# 集合支持数学集合操作,包括并集、交集和差集。这些操作使用 Set
模块的函数或等效运算符来执行。
let setA = set [1; 2; 3; 4; 5] let setB = set [4; 5; 6; 7; 8] // Union (elements in either set) let unionAB = Set.union setA setB printfn "Union: %A" unionAB // Alternative union syntax let unionAB2 = setA + setB printfn "Union with +: %A" unionAB2 // Intersection (elements in both sets) let intersectAB = Set.intersect setA setB printfn "Intersection: %A" intersectAB // Difference (elements in first set but not second) let diffAB = Set.difference setA setB printfn "Difference A-B: %A" diffAB // Symmetric difference (elements in either set but not both) let symDiffAB = (setA - setB) + (setB - setA) printfn "Symmetric difference: %A" symDiffAB
此示例演示了基本集合操作。+
运算符可用于并集,而 -
用于差集。请注意,对称差集不是内置的,但可以从其他操作构建。
λ dotnet fsi set_operations.fsx Union: set [1; 2; 3; 4; 5; 6; 7; 8] Union with +: set [1; 2; 3; 4; 5; 6; 7; 8] Intersection: set [4; 5] Difference A-B: set [1; 2; 3] Symmetric difference: set [1; 2; 3; 6; 7; 8]
集合比较和子集操作
集合可以进行相等性和子集关系的比较。F# 提供了函数来检查一个集合是否是另一个集合的子集或超集,或者它们是否包含完全相同的元素。
let setX = set [1; 2; 3; 4] let setY = set [3; 4; 5; 6] let setZ = set [3; 4] // Equality printfn "X equals Y? %b" (setX = setY) printfn "X equals X? %b" (setX = setX) // Subset checks printfn "Z subset of X? %b" (Set.isSubset setZ setX) printfn "Z proper subset of X? %b" (Set.isProperSubset setZ setX) printfn "Z subset of Y? %b" (Set.isSubset setZ setY) // Superset checks printfn "X superset of Z? %b" (Set.isSuperset setX setZ) printfn "Y superset of Z? %b" (Set.isSuperset setY setZ)
该示例展示了如何比较集合。isSubset
检查一个集合的所有元素是否在另一个集合中,而 isProperSubset
要求集合不同。isSuperset
是 isSubset
的逆运算。
λ dotnet fsi set_comparisons.fsx X equals Y? false X equals X? true Z subset of X? true Z proper subset of X? true Z subset of Y? true X superset of Z? true Y superset of Z? true
集合转换和过滤
可以使用 map
和 filter
等高阶函数对集合进行转换和过滤。这些操作会返回包含转换或过滤后元素的新集合。
let numbers = set [1; 2; 3; 4; 5; 6; 7; 8; 9; 10] // Mapping a function over a set let squares = Set.map (fun x -> x * x) numbers printfn "Squares: %A" squares // Filtering elements let evens = Set.filter (fun x -> x % 2 = 0) numbers printfn "Evens: %A" evens // Folding (reducing) a set let sum = Set.fold (fun acc x -> acc + x) 0 numbers printfn "Sum: %d" sum // Iterating over a set printf "Elements: " Set.iter (fun x -> printf "%d " x) numbers printfn ""
此代码演示了集合上的函数式转换。map
将函数应用于每个元素,filter
选择匹配谓词的元素,fold
将集合简化为单个值,iter
对每个元素执行操作。
λ dotnet fsi set_transformations.fsx Squares: set [1; 4; 9; 16; 25; 36; 49; 64; 81; 100] Evens: set [2; 4; 6; 8; 10] Sum: 55 Elements: 1 2 3 4 5 6 7 8 9 10
使用自定义类型
集合可以包含自定义类型,但这些类型必须支持比较。对于记录和区分联合,如果所有组成类型都支持比较,F# 会自动生成比较实现。
type Person = { Name: string Age: int } let people = set [ { Name = "Alice"; Age = 30 } { Name = "Bob"; Age = 25 } { Name = "Alice"; Age = 30 } // Duplicate { Name = "Charlie"; Age = 35 } ] printfn "People set: %A" people printfn "Count: %d" people.Count type Shape = | Circle of radius: float | Rectangle of width: float * height: float let shapes = set [ Circle 2.5 Rectangle (3.0, 4.0) Circle 2.5 // Duplicate Rectangle (1.0, 2.0) ] printfn "Shapes set: %A" shapes printfn "Contains Circle 2.5? %b" (shapes.Contains (Circle 2.5))
此示例展示了包含自定义类型的集合。Person
记录和 Shape
区分联合自动支持比较,因此它们可以在集合中使用。重复项会根据比较自动删除。
λ dotnet fsi custom_types.fsx People set: set [{ Name = "Alice" Age = 30; }; { Name = "Bob" Age = 25; }; { Name = "Charlie" Age = 35; }] Count: 3 Shapes set: set [Circle 2.5; Rectangle (1.0, 2.0); Rectangle (3.0, 4.0)] Contains Circle 2.5? true
F# 集合是强大的不可变集合,提供高效的查找操作并支持数学集合操作。其不可变性使其成为函数式编程模式的理想选择,而其作为平衡二叉树的实现则确保了良好的性能。无论你需要处理唯一的数据集合还是执行集合论运算,F# 集合都提供了稳健的解决方案。