F# For Dummys - Day 15 Collections Set
Tags: fsharp
Published: 2024-05-27 08:39:41

Today we learn Set, an immutable collection that automatically ensures all its elements are unique and sorted
#### Create Set
- Using set notation
```f#
let numberSet = set [1; 3; 5; 4; 2; 3]
printfn "numberSet: %A" numberSet // numberSet: set [1; 2; 3; 4; 5]
```
- from List
```f#
let fruits = Set.ofList ["apple"; "banana"; "orange"; "apple"]
printfn "Fruits: %A" fruits
```
- Set.empty create an empty Set
```f#
let emptySet = Set.empty
printfn "emptySet: %A" emptySet // emptySet: set []
```
#### Get element not support
```f#
let fruits = Set.ofList ["apple"; "banana"; "orange"]
printfn "Fruits first element: %A" fruits.[0]
```
raise Error: The type 'Set<_>' does not define the field, constructor or member 'Item'</br>
#### Add/Remove element
- Set.add</br>
Returns a new set with an element added to the set. No exception is raised if the set already contains the given element
```f#
let set = Set.empty.Add(1).Add(1).Add(2)
printfn $"The new set is: {set}"
```
- Set.remove</br>
Returns a new set with the given element removed. No exception is raised if the set doesn't contain the given element
```f#
let set = Set.empty.Add(1).Add(2).Add(3)
printfn $"The set without 1 is {Set.remove 1 set}" // The set without 1 is set [2; 3]
printfn $"The set without 1 is {Set.remove 4 set}" // The set without 1 is set [1; 2; 3]
```
we can see set itself didn't change after remove 1
#### Loop Set
- for ... in
```f#
let fruits = Set.ofList ["apple"; "banana"; "orange"; "grape"]

for fruit in fruits do
    printfn "Fruit: %s" fruit
```
- Set.iter</br>
Applies the given function to each element of the set, in order according to the comparison function
```f#
let set = Set.empty.Add(1).Add(2).Add(3)
Set.iter (fun x -> printfn $"The set contains {x}") set
```
#### Element operation
- Contains</br>
syntax: Set.Contains element set</br>
Evaluates to "true" if the given element is in the given set
```f#
let set = Set.empty.Add(2).Add(3)
printfn $"Does the set contain 1? {Set.contains 1 set}" // Does the set contain 1? false
```
use *Instance Member Function*
```f#
let set = Set.empty.Add(2).Add(3)
printfn $"Does the set contain 1? {set.Contains(1)}"  // Does the set contain 1? false
```
- exists</br>
syntax: Set.exists predicate set</br>
Tests if any element of the collection satisfies the given predicate
```f#
let set = Set.empty.Add(1).Add(2).Add(3)
printfn $"Does the set contain even number? {Set.exists (fun x -> x % 2 = 0) set}" // Does the set contain even number? true
```
- filter</br>
syntax: Set.filter predicate set</br>
Returns a new collection containing only the elements of the collection for which the given predicate returns True
```f#
let set = Set.empty.Add(1).Add(2).Add(3).Add(4)
printfn $"The set with even numbers is {Set.filter (fun x -> x % 2 = 0) set}" // The set with even numbers is set [2; 4]
```
#### Set operation

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gdrin1ogfc1f5gslhm7s.png)

Lucy and Lily having breakfast: </br>
Lucy have milk, boiled egg and sausages, Lily have milk, bacon and fried egg, </br>
we can define their food list by 2 Sets: set ["milk", "boiled egg", "sausages"], set ["milk", "bacon", "fried egg"]
- union</br>
union is all the elements in 2 Sets
```f#
let LucyBreakfastSet = set ["milk"; "boiled egg"; "sausages"]
let LilyBreakfastSet = set ["milk"; "bacon"; "fried egg"]
printfn $"The union of {LucyBreakfastSet} and {LilyBreakfastSet} is {(Set.union LucyBreakfastSet LilyBreakfastSet)}"
```
the union is expected to be "milk", "boiled egg", "sausages", "bacon", "fried egg"</br>
results: The union of set [boiled egg; milk; sausages] and set [bacon; fried egg; milk] is set [bacon; boiled egg; fried egg; milk; sausages]
- intersect</br>
Computes the intersection of the two sets, the common elements they share
```f#
let LucyBreakfastSet = set ["milk"; "boiled egg"; "sausages"]
let LilyBreakfastSet = set ["milk"; "bacon"; "fried egg"]
printfn $"The intersect of {LucyBreakfastSet} and {LilyBreakfastSet} is {(Set.intersect LucyBreakfastSet LilyBreakfastSet)}"
```
the intersect is expected to be "milk"</br>
results: The intersect of set [boiled egg; milk; sausages] and set [bacon; fried egg; milk] is set [milk]
- difference</br>
difference returns a new set with the elements of the second set removed from the first set, which is the left colored part in the picture (A left B right)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7ypjsbvgujcc811bx31m.jpg)

if we put Lucy's breakfast in the first place
```f#
let LucyBreakfastSet = set ["milk"; "boiled egg"; "sausages"]
let LilyBreakfastSet = set ["milk"; "bacon"; "fried egg"]
printfn $"The difference of {LucyBreakfastSet} and {LilyBreakfastSet} is {(Set.difference LucyBreakfastSet LilyBreakfastSet)}"
```
we got "boiled egg"; "sausages"
result: The difference of set [boiled egg; milk; sausages] and set [bacon; fried egg; milk] is set [boiled egg; sausages]</br>
*Set.difference LucyBreakfastSet LilyBreakfastSet* is equivalent to *LucyBreakfastSet - LilyBreakfastSet*</br>
we can understand like this: remove the food Lily also had in Lucy's food
```f#
let LucyBreakfastSet = set ["milk"; "boiled egg"; "sausages"]
let LilyBreakfastSet = set ["milk"; "bacon"; "fried egg"]
printfn $"The difference of {LucyBreakfastSet} and {LilyBreakfastSet} is {(LucyBreakfastSet - LilyBreakfastSet)}"
```