Skip to content

Commit 44c0a79

Browse files
committed
feat(hashset): add intersection and difference methods to hashset
1 parent 0cdca5b commit 44c0a79

File tree

3 files changed

+96
-0
lines changed

3 files changed

+96
-0
lines changed

immut/hashset/HAMT.mbt

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,56 @@ pub fn union[K : Eq + Hash](self : T[K], other : T[K]) -> T[K] {
192192
}
193193
}
194194

195+
///|
196+
/// Intersect two hashsets
197+
pub fn intersection[K : Eq + Hash](self : T[K], other : T[K]) -> T[K] {
198+
match (self, other) {
199+
(_, Empty) => Empty
200+
(Empty, _) => Empty
201+
(Leaf(k), _) => if other.contains(k) { Leaf(k) } else { Empty }
202+
(_, Leaf(k)) => if self.contains(k) { Leaf(k) } else { Empty }
203+
(Branch(sa1), Branch(sa2)) => {
204+
let res = sa1.intersection(sa2, fn(m1, m2) { m1.intersection(m2) })
205+
if res.size() == 0 {
206+
Empty
207+
} else {
208+
Branch(res)
209+
}
210+
}
211+
(_, _) =>
212+
self
213+
.iter()
214+
.fold(init=Empty, fn(m, k) {
215+
if other.contains(k) {
216+
m.add(k)
217+
} else {
218+
m
219+
}
220+
})
221+
}
222+
}
223+
224+
///|
225+
/// Difference of two hashsets: elements in `self` but not in `other`
226+
pub fn difference[K : Eq + Hash](self : T[K], other : T[K]) -> T[K] {
227+
match (self, other) {
228+
(Empty, _) => Empty
229+
(_, Empty) => self
230+
(Leaf(k), _) => if other.contains(k) { Empty } else { Leaf(k) }
231+
(Branch(sa1), Branch(sa2)) => Branch(sa1.difference(sa2))
232+
(_, _) =>
233+
self
234+
.iter()
235+
.fold(init=Empty, fn(m, k) {
236+
if other.contains(k) {
237+
m
238+
} else {
239+
m.add(k)
240+
}
241+
})
242+
}
243+
}
244+
195245
///|
196246
/// Returns true if the hash set is empty.
197247
pub fn is_empty[A](self : T[A]) -> Bool {

immut/hashset/HAMT_test.mbt

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,3 +217,43 @@ test "union 2 hashsets" {
217217
let set4 = @hashset.of([1, 2, 3, 4, 5])
218218
inspect!(set3 == set4, content="true")
219219
}
220+
221+
///|
222+
test "@hashset.intersection with overlapping sets" {
223+
let set1 = @hashset.of([1, 2, 3, 4])
224+
let set2 = @hashset.of([3, 4, 5, 6])
225+
let result = set1.intersection(set2)
226+
inspect!(result, content="@immut/hashset.of([3, 4])")
227+
}
228+
229+
///|
230+
test "@hashset.intersection with disjoint sets" {
231+
let set1 = @hashset.of([1, 2])
232+
let set2 = @hashset.of([3, 4])
233+
let result = set1.intersection(set2)
234+
inspect!(result.is_empty(), content="true")
235+
}
236+
237+
///|
238+
test "@hashset.intersection with one empty set" {
239+
let set1 = @hashset.of([1, 2, 3])
240+
let set2 = @hashset.new()
241+
let result = set1.intersection(set2)
242+
inspect!(result.is_empty(), content="true")
243+
}
244+
245+
///|
246+
test "@hashset.intersection with identical sets" {
247+
let set1 = @hashset.of([1, 2, 3])
248+
let set2 = @hashset.of([1, 2, 3])
249+
let result = set1.intersection(set2)
250+
inspect!(result == set1, content="true")
251+
}
252+
253+
///|
254+
test "@hashset.intersection with subset" {
255+
let set1 = @hashset.of([1, 2, 3, 4])
256+
let set2 = @hashset.of([2, 3])
257+
let result = set1.intersection(set2)
258+
inspect!(result == @hashset.of([2, 3]), content="true")
259+
}

immut/hashset/hashset.mbti

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ fn size[A](T[A]) -> Int
2929

3030
fn union[K : Eq + Hash](T[K], T[K]) -> T[K]
3131

32+
fn intersection[K : Eq + Hash](T[K], T[K]) -> T[K]
33+
34+
fn difference[K : Eq + Hash](T[K], T[K]) -> T[K]
35+
3236
// Types and methods
3337
type T[A]
3438
impl T {
@@ -40,6 +44,8 @@ impl T {
4044
remove[A : Eq + Hash](Self[A], A) -> Self[A]
4145
size[A](Self[A]) -> Int
4246
union[K : Eq + Hash](Self[K], Self[K]) -> Self[K]
47+
intersection[K : Eq + Hash](Self[K], Self[K]) -> Self[K]
48+
difference[K : Eq + Hash](Self[K], Self[K]) -> Self[K]
4349
}
4450
impl[A : Eq] Eq for T[A]
4551
impl[A : Hash] Hash for T[A]

0 commit comments

Comments
 (0)