Haskell #18.5 Module Set

 

Data.Set

legosets

Module Data.Set cho ta các tập hợp. Giống như tập hợp toán học ấy. Tất cả các phần tử trong tập hợp đều là duy nhất. Và vì bản chất là chúng được lập bằng cấu trúc cây (rất giống với ánh xạ trong Data.Map), nên chúng có thứ tự. Việc kiểm tra quan hệ thuộc, chèn phần tử, xóa phần tử, v.v. nhanh hơn nhiều so với những thao tác tương tự trên danh sách. Phép thao tác thường gặp nhất khi làm việc với tập hợp là chèn vào tập hợp, kiểm tra xem phần tử có thuộc tập hợp hay không, và chuyển đổi tập hợp thành danh sách.

Vì các tên hàm trong Data.Set xung đột [trùng lặp] nhiều với tên trong Prelude và Data.List, nên ta cần nhập có chọn lọc.

Hãy viết câu lệnh nhập này trong file mã lệnh:

import qualified Data.Set as Set

Rồi sau đó nạp file mã lệnh trong GHCI.

Giả sử rằng ta có hai đoạn văn bản chữ. Ta cần tìm ra xem những kí tự nào được dùng trong cả hai đoạn đó.

text1 = "I just had an anime dream. Anime... Reality... Are they so different?"
text2 = "The old man left his garbage can out and now his trash is all over my lawn!"

Hàm fromList hoạt động rất giống với những gì bạn trông đợi. Nó nhận vòa một danh sách rồi chuyển đổi nó thành một tập hợp.

ghci> let set1 = Set.fromList text1
ghci> let set2 = Set.fromList text2
ghci> set1
fromList " .?AIRadefhijlmnorstuy"
ghci> set2
fromList " !Tabcdefghilmnorstuvwy"

Như bạn đã thấy, các phần tử được xếp thứ tự và mỗi phần tử là duy nhất. Bây giờ hãy dùng hàm intersection để xem những phần tử nào có chung trong cả hai tập hợp này.

ghci> Set.intersection set1 set2
fromList " adefhilmnorstuy"

Ta có thể dùng hàm difference để xem những chữu cái nào có trong tập hợp thứ nhất nhưng không có trong tập hợp thứ hai, và ngược lại.

ghci> Set.difference set1 set2
fromList ".?AIRj"
ghci> Set.difference set2 set1
fromList "!Tbcgvw"

Hoặc là ta có thể xem những chữ cái duy nhất dùng trong hai câu này [không cần chung] bằng hàm union.

ghci> Set.union set1 set2
fromList " !.?AIRTabcdefghijlmnorstuvwy"

Các hàm nullsizememberemptysingletoninsert và delete, tất cả đều hoạt động theo cách bạn trông đợi.

ghci> Set.null Set.empty
True
ghci> Set.null $ Set.fromList [3,4,5,5,4,3]
False
ghci> Set.size $ Set.fromList [3,4,5,3,4,5]
3
ghci> Set.singleton 9
fromList [9]
ghci> Set.insert 4 $ Set.fromList [9,3,8,1]
fromList [1,3,4,8,9]
ghci> Set.insert 8 $ Set.fromList [5..10]
fromList [5,6,7,8,9,10]
ghci> Set.delete 4 $ Set.fromList [3,4,5,4,3,4,5]
fromList [3,5]

Ta cũng có thể kiểm tra các mối quan hệ tập con hoặc tập con thực sự. Tập hợp A được gọi là tập con của tập B nếu B chứa tất cả những phần tử có trong A. Tập A được gọi là tập con thực sự của tập B nếu B chứa tất cả những phần tử của A, ngoài ra còn những phần tử khác nữa.

ghci> Set.fromList [2,3,4] `Set.isSubsetOf` Set.fromList [1,2,3,4,5]
True
ghci> Set.fromList [1,2,3,4,5] `Set.isSubsetOf` Set.fromList [1,2,3,4,5]
True
ghci> Set.fromList [1,2,3,4,5] `Set.isProperSubsetOf` Set.fromList [1,2,3,4,5]
False
ghci> Set.fromList [2,3,4,8] `Set.isSubsetOf` Set.fromList [1,2,3,4,5]
False

Ta cũng có thể map [ánh xạ] trên tập hợp và filter [lọc] chúng.

ghci> Set.filter odd $ Set.fromList [3,4,5,6,7,2,3,4]
fromList [3,5,7]
ghci> Set.map (+1) $ Set.fromList [3,4,5,6,7,2,3,4]
fromList [3,4,5,6,7,8]

Tập hợp thường được dùng để gạt một tập hợp những phần tử trùng lặp khỏi một danh sách gốc bằng cách đầu tiên là chuyển nó về một tập hợp, bằng hàm fromList và rồi chuyển ngược nó về bằng toList. Hàm nub trong Data.List đã làm việc đó, nhưng việc gạt bỏ trùng lặp trên danh sách lớn sẽ được thực hiện nhanh hơn nhiều nếu bạn nhồi nó vào một tập hợp rồi chuyển ngược về danh sách bằng cách dùng nub. Nhưng để dùng nub chỉ cần kiểu của các phần tử danh sách thuộc về lớp Eq, còn nếu muốn nhồi các phần tử vào tập hợp thì kiểu của danh sách phải thuộc về Ord.

ghci> let setNub xs = Set.toList $ Set.fromList xs
ghci> setNub "HEY WHATS CRACKALACKIN"
" ACEHIKLNRSTWY"
ghci> nub "HEY WHATS CRACKALACKIN"
"HEY WATSCRKLIN"

Nhìn chung, setNub nhanh hơn nub khi hoạt động trên danh sách lớn, song như bạn có thể thấy, nub bảo toàn thứ tự các phần tử trong danh sách, còn setNub thì không.