Тип Set или множество в языке F# представляет набор данных, основанный на бинарных деревьях, который хранит только уникальные элементы.
Для определения множества применяется оператор set, которому передается последовательность значений:
let people = set ["Tom"; "Bob"; "Sam"] printfn $"People: {people}" // People: set [Tom, Bob, Sam]
В данном случае в качестве последовательности применяется список из трех строк, соответственно множество будет содержать три строки. С помощью функции printfn
можно вывести множество на консоль.
Для создания множества в объектно-ориентированном стиле можно применять конструктор типа Set, в который передается последовательность элементов:
let employees = ["Tom"; "Bob"; "Sam"] let people = Set(employees) printfn $"People: {people}" // People: set ["Tom"; "Bob"; "Sam"]
Здесь аналогично создается множество people а основе списка employees.
Стоит отметить, что тип Set является обобщенным, поэтому конкретные множества типизируются типом его элементов. Так, в примере выше в реальности создается объект
Set<'string>
, и мы могли бы явным образом указать тип:
let people: Set<'string> = set ["Tom"; "Bob"; "Sam"] printfn $"People: {people}" // People: set ["Tom"; "Bob"; "Sam"]
Для создания множество также модуль Set предоставляет ряд функций. Так, функция Set.empty создает пустое множество:
let people = Set.empty
Также есть ряд функций для создания множества из конкретных последовательностей:
Set.ofArray
: создает множество из массива
Set.ofList
: создает множество из списка
Set.ofSeq
: создает множество из последовательности
let set1 = Set.ofArray [|"Tom"; "Bob"; "Sam"|] printfn $"{set1}" // set [Tom; Bob; Sam] let set2 = Set.ofList ["Tom"; "Bob"; "Sam"] printfn $"{set2}" // set [Bob; Sam; Tom] let set3 = Set.ofSeq["Tom", "Bob", "Sam"] printfn $"{set3}" // set [(Tom, Bob, Sam)]
Причем важно понимать, что множество - это набор уникальных значений, дубликатов в нем быть не может. Например:
let usersList = ["Tom"; "Bob"; "Sam"; "Bob"; "Tom"; "Sam"] // список let usersSet = set usersList // множество printfn $"{usersList}" // ["Tom"; "Bob"; "Sam"; "Bob"; "Tom"; "Sam"] printfn $"{usersSet}" // set [Bob; Sam; Tom]
В данном случае множество создается на основе списка с дублями. Однако, как мы можем увидеть, созданное множество не содержит дублей, а только уникальные элементы. Подобная техника нередко применяется для отсеивания дублей в различных языказ программирования.
Другой важный момент - упорядочивание элементов. Если вы обратите внимание на консольный вывод множества, то увидите, что элементы в нем упорядочены по возрастанию, хотя в изначальном списке они были расположены в другом порядке:
set [Bob; Sam; Tom]
Тип Set предоставляет ряд методов для управления множествами:
Add: возвращает копию множества, в которую добавлен новый элемент.
Contains: возвращает true
, если множество содержит определенный элемент
Count: возвращает количество элементов множества
IsEmpty: возвращает true
, если множество пустое.
IsProperSubsetOf: возвращает true
, если второе множество (из параметра) содержит первое множество,
и при этом второе множество содержит как минимум один элемент, которого нет в первом
IsProperSupersetOf: возвращает true
, если первое множество содержит второе множество (из параметра),
и при этом первое множество содержит как минимум один элемент, которого нет в втором
IsSubsetOf: возвращает true
, если второе множество (из параметра) содержит первое множество
IsSupersetOf: возвращает true
, если первое множество содержит второе множество (из параметра)
MaximumElement: возвращает наибольший элемент множества.
MinimumElement: возвращает наименьший элемент.
Remove: возвращает копию множества, из которого удален определенный элемент.
Для перебора множества можно использовать циклические конструкции, например, цикл for-in:
let people = set ["Tom"; "Bob"; "Sam"] for person in people do printfn "%s" person
Кроме того, модуль Set предоставляет функцию Set.iter:
Set.iter action set
Ее первый параметр - функция-действие, в которую передается каждый элемент множества, а второй параметр - само множество. Применение:
let people = set ["Tom"; "Bob"; "Sam"] Set.iter (fun p -> printfn "%s" p) people
Для получения размера множества можно использовать либо функцию Set.count, в которую передается множество, либо свойство Count типа Set:
let people = set ["Tom"; "Bob"; "Sam"] printfn "Count: %d" (Set.count people) printfn "Count: %d" (people.Count)
С помощью функции Set.isEmpty и свойства IsEmpty типа Set можно проверить множество на наличие элементов - если множество пустое, они возвращают true
:
let people = set ["Tom"; "Bob"; "Sam"] printfn "people is empty? %b" (Set.isEmpty people) printfn "people is empty? %b" (people.IsEmpty) let students = Set.empty printfn "students is empty? %b" (Set.isEmpty students) printfn "students is empty? %b" (students.IsEmpty)
Для проверки наличия элемента во множестве применяется функция Set.contains
Set.contains element set
Применение:
let people = set ["Tom"; "Bob"; "Sam"] printfn "Sam in people? %b" (Set.contains "Sam" people) // true printfn "Alex in people? %b" (Set.contains "Alex" people) // false
Также в качестве альтернативы можно использовать метод Contains() объекта Set:
let people = set ["Tom"; "Bob"; "Sam"] printfn "Sam in people? %b" (people.Contains("Sam")) // true printfn "Alex in people? %b" (people.Contains("Alex")) // false
Для проверки элементов множества модуль Set предоставляет еще две функции:
Set.exists predicate set
: возвращает true
, если хотя бы один элемент множества удовлетворяет условию
Set.forall predicate set
: возвращает true
, если хотя бы один элемент множества удовлетворяет условию
Обе функции в качестве первого параметра принимают функцию-условие, которая получает каждый элемент множества и возвращает true
или false
в зависимости от того,
соответствует ли элемент условию. Второй параметр - само множество. Применение:
let numbers = set [1; 2; 3; 4; 5; 6] // если ли элементы больше 3 printfn "%b" (Set.exists (fun n -> n > 3) numbers) // true // если ли элементы больше 9 printfn "%b" (Set.exists (fun n -> n > 9) numbers) // false // все ли элементы больше 3 printfn "%b" (Set.forall (fun n -> n > 3) numbers) // false // все ли элементы больше 0 printfn "%b" (Set.forall (fun n -> n > 0) numbers) // true
Для добавления новых элементов применяется функция Set.add:
Set.add value set
Функции передается добавляемое значение и множество. Но стоит учитывать, что множество - это неизменяемая коллекция, и в реальности будет создаваться новое множество, которое будет включать элементы оригинального множества и добавляемый элемент:
let people_old = set ["Tom"; "Bob"; "Sam"] let people_new = Set.add "Alice" people_old // Добавляем в множество строку "Alice" printfn $"Original set: {people_old}" // set ["Bob"; "Sam"; "Tom"] printfn $"New set: {people_new}" // set ["Alice";"Bob"; "Sam"; "Tom"]
В качестве альтернативы можно использовать метод Add() объекта Set:
let people_old = set ["Tom"; "Bob"; "Sam"] let people_new = people_old.Add("Alice") printfn $"New set: {people_new}" // set ["Alice";"Bob"; "Sam"; "Tom"]
Для удаления элемента из множества модуль Set предоставляет функцию Set.remove, в которую передается удаляемый элемент и множество:
Set.remove value set
И опять же, как и в случае с добавлением, эта функция не изменяет начальное множество, а возвращает новое, которое не содержит удаляемый элемент. Например:
let people_old = set ["Tom"; "Bob"; "Sam"] let people_new = Set.remove "Sam" people_old // удаляем строку "Sam" printfn $"Original set: {people_old}" // set ["Bob"; "Sam"; "Tom"] printfn $"New set: {people_new}" // set ["Bob"; "Tom"]
Также для удаления можно использовать метод Remove() объекта Set:
let people_old = set ["Tom"; "Bob"; "Sam"] let people_new = people_old.Remove("Sam") printfn $"New set: {people_new}" // set ["Bob"; "Tom"]
Для фильтрации множества применяется функция :
Set.filter predicate set
Первый параметр функции - функция, которая проверяет каждый элемент на соответствие условию и при соответствии возвращает true
, а второй параметр - фильтруемое множество.
let numbers = set [-6; -5; -4; -3; -2; -1; 0; 1; 2; 3; 4; 5; 6] // получаем только четные числа let filteredSet = Set.filter (fun n -> n%2=0) numbers printfn "%A" filteredSet // set [-6; -4; -2; 0; 2; 4; 6]
Функция Set.partition позволяет получить два множества - одно с элементами, которые соответствуют условию, а второе множество с элементами, которые ему не соответствуют. Результатом является кортеж из двух множеств:
let numbers = set [-6; -5; -4; -3; -2; -1; 0; 1; 2; 3; 4; 5; 6] // разбиваем на два множества - с четными и нечетными числами let sets = Set.partition (fun n -> n%2=0) numbers printfn "%A" (fst sets) // set [-6; -4; -2; 0; 2; 4; 6] printfn "%A" (snd sets) // set [-5; -3; -1; 1; 3; 5]
А для преобразования множества применяется функция Set.map:
Set.map mapping set
В качестве первого параметра передается функция, которая получает каждый элемент множества и возвращает измененный элемент:
let numbers = set [0; 1; 2; 3; 4; 5; 6] // возведем все числа в квадрат let squares = Set.map (fun n -> n * n) numbers printfn "%A" squares // set [0; 1; 4; 9; 16; 25; 36]
F# позволяет легко получить минимальный и максимальный элементы множества. Для этого модуль Set предоставляет соответственно функции Set.minElement и Set.maxElement. В качестве альтернативы также можно использовать свойства MinimumElement и MaximumElement объекта Set.
Поскольку минимальный элемент - это тот, который условно меньше всех, то фактически он эквивалентен самому первому элементу множества. Аналогично максимальный элемент представляет последний элемент множества. Например:
let people = set ["Tom"; "Bob"; "Sam"] printfn "Min: %s" (Set.minElement people) // Min: Bob printfn "Min: %s" people.MinimumElement // Min: Bob printfn "Max: %s" (Set.maxElement people) // Max: Tom printfn "Max: %s" people.MaximumElement // Max: Tom
Кроме общих функций модуль Set предоставляет ряд функций для операций с двумя множествами:
Set.difference set1 set2
: возвращает разницу двух множеств (элементы, которые есть в первом, но отсутствуют во втором множестве)
Set.intersect set1 set2
: возвращает пересечение двух множеств (элементы, которые есть одновременно и в первом, и во втором множествам)
Set.intersectMany sets
: возвращает пересечение всех множеств
Set.union set1 set2
: возвращает объединение двух множеств (все элементы обоих множеств)
Set.unionMany sets
: возвращает объединение всех множеств
Все эти функции возращают результат в виде нового множества.
И также есть ряд функций для проверки отношения множеств:
Set.isProperSubset set1 set2
: возвращает true
, если второе множество содержит первое множество,
и при этом второе множество содержит как минимум один элемент, которого нет в первом
Set.isProperSuperset set1 set2
: возвращает true
, если первое множество содержит второе множество,
и при этом первое множество содержит как минимум один элемент, которого нет в втором
Set.isSubset set1 set2
: возвращает true
, если второе множество содержит первое множество
Set.isSuperset set1 set2
: возвращает true
, если первое множество содержит второе множество
let students = set ["Tom"; "Bob"; "Sam"] let employees = set ["Tom"; "Bob"; "Alex"; "Mike"] // объединение множеств let union1 = Set.union students employees printfn $"{union}" // set [Alex; Bob; Mike; Sam; Tom]
В качестве альтернативы для объединения множеств можно применять операцию +:
let students = set ["Tom"; "Bob"; "Sam"] let employees = set ["Tom"; "Bob"; "Alex"; "Mike"] let union = students + employees printfn $"{union}" // set [Alex; Bob; Mike; Sam; Tom]
let students = set ["Tom"; "Bob"; "Sam"] let employees = set ["Tom"; "Bob"; "Alex"; "Mike"] let intersection = Set.intersect students employees printfn $"{intersection}" // set ["Bob", "Tom"]
let students = set ["Tom"; "Bob"; "Sam"] let employees = set ["Tom"; "Bob"; "Alex"; "Mike"] let diff = Set.difference students employees printfn $"{diff}" // set [Sam]
В качестве альтернативы для разности множеств можно применять операцию -:
let students = set ["Tom"; "Bob"; "Sam"] let employees = set ["Tom"; "Bob"; "Alex"; "Mike"] let diff = students - employees printfn $"{diff}" // set [Sam]
Функция Set.isSubset и метод IsSubsetOf() объекта Set возвращают true
, если первое множество содержится во втором
(то есть первое множество является подмножеством второго):
let students = set ["Tom"; "Bob"; "Sam"] let employees = set ["Tom"; "Bob"; "Alex"; "Mike"] // является ли множество подмножеством let workingStudents = Set.intersect students employees // set ["Bob", "Tom"] printfn "%b" (Set.isSubset workingStudents students) // true printfn "%b" (workingStudents.IsSubsetOf(students)) // true printfn "%b" (Set.isSubset employees students) // false printfn "%b" (employees.IsSubsetOf(students)) // false
Функция Set.isSuperset и метод IsSupersetOf() объекта Set возвращают true
, если второе множество содержится в первом
(то есть первое множество является надмножеством второго):
let students = set ["Tom"; "Bob"; "Sam"] let employees = set ["Tom"; "Bob"; "Alex"; "Mike"] // является ли множество надмножеством let people = Set.union students employees // set ["Alex"; "Bob"; "Mike"; "Sam"; "Tom"] printfn "%b" (Set.isSuperset people students) // true printfn "%b" (people.IsSupersetOf(students)) // true printfn "%b" (Set.isSuperset employees students) // false printfn "%b" (employees.IsSupersetOf(students)) // false