From 2d237505c735fc5db38756fe00312737ef4013db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Bene=C5=A1?= Date: Fri, 4 Oct 2024 15:40:51 +0200 Subject: [PATCH] Add intersection for treeset and treemap, incl. tests --- examples/stdlib/set/unique.check | 12 ++++++---- examples/stdlib/set/unique.effekt | 40 ++++++++++++++++++++++--------- libraries/common/map.effekt | 35 ++++++++++++++++++++++++--- libraries/common/set.effekt | 11 +++++++++ 4 files changed, 80 insertions(+), 18 deletions(-) diff --git a/examples/stdlib/set/unique.check b/examples/stdlib/set/unique.check index 72ee25591..819832611 100644 --- a/examples/stdlib/set/unique.check +++ b/examples/stdlib/set/unique.check @@ -4,15 +4,19 @@ you: true see: false do: true Effekt: true + Cons(Effekt, Cons(and, Cons(ask, Cons(but, Cons(can, Cons(do, Cons(fellow, Cons(for, Cons(language, Cons(man, Cons(my, Cons(not, Cons(of, Cons(programmers, Cons(programs, Cons(so, Cons(the, Cons(together, Cons(we, Cons(what, Cons(will, Cons(world, Cons(you, Cons(your, Nil())))))))))))))))))))))))) -true +sorted Cons(Effekt, Cons(and, Cons(ask, Cons(but, Cons(can, Cons(do, Cons(fellow, Cons(for, Cons(language, Cons(man, Cons(my, Cons(not, Cons(of, Cons(programmers, Cons(programs, Cons(so, Cons(the, Cons(together, Cons(we, Cons(what, Cons(will, Cons(world, Cons(you, Cons(your, Nil())))))))))))))))))))))))) -true +sorted + Cons(after, Cons(around, Cons(better, Cons(do, Cons(ever, Cons(faster, Cons(harder, Cons(hour, Cons(is, Cons(it, Cons(make, Cons(makes, Cons(more, Cons(never, Cons(over, Cons(stronger, Cons(than, Cons(the, Cons(us, Cons(work, Cons(world, Nil()))))))))))))))))))))) -true +sorted lyrics / speech: Cons(after, Cons(around, Cons(better, Cons(ever, Cons(faster, Cons(harder, Cons(hour, Cons(is, Cons(it, Cons(make, Cons(makes, Cons(more, Cons(never, Cons(over, Cons(stronger, Cons(than, Cons(us, Cons(work, Nil())))))))))))))))))) speech / lyrics: -Cons(after, Cons(around, Cons(better, Cons(ever, Cons(faster, Cons(harder, Cons(hour, Cons(is, Cons(it, Cons(make, Cons(makes, Cons(more, Cons(never, Cons(over, Cons(stronger, Cons(than, Cons(us, Cons(work, Nil())))))))))))))))))) +Cons(Effekt, Cons(and, Cons(ask, Cons(but, Cons(can, Cons(fellow, Cons(for, Cons(language, Cons(man, Cons(my, Cons(not, Cons(of, Cons(programmers, Cons(programs, Cons(so, Cons(together, Cons(we, Cons(what, Cons(will, Cons(you, Cons(your, Nil()))))))))))))))))))))) +speech n lyrics: +Cons(do, Cons(the, Cons(world, Nil()))) speech u lyrics: Cons(Effekt, Cons(after, Cons(and, Cons(around, Cons(ask, Cons(better, Cons(but, Cons(can, Cons(do, Cons(ever, Cons(faster, Cons(fellow, Cons(for, Cons(harder, Cons(hour, Cons(is, Cons(it, Cons(language, Cons(make, Cons(makes, Cons(man, Cons(more, Cons(my, Cons(never, Cons(not, Cons(of, Cons(over, Cons(programmers, Cons(programs, Cons(so, Cons(stronger, Cons(than, Cons(the, Cons(together, Cons(us, Cons(we, Cons(what, Cons(will, Cons(work, Cons(world, Cons(you, Cons(your, Nil())))))))))))))))))))))))))))))))))))))))))) \ No newline at end of file diff --git a/examples/stdlib/set/unique.effekt b/examples/stdlib/set/unique.effekt index 8a0c6fc64..a7b000b40 100644 --- a/examples/stdlib/set/unique.effekt +++ b/examples/stdlib/set/unique.effekt @@ -36,17 +36,28 @@ def main() = { test("Effekt") // --- + println("") + + def testSorted(s: Set[String]) = { + val sorted = s.toList.isSortedBy { (x, y) => x <= y } + if (sorted) { + println("sorted") + } else { + println("unsorted") + } + } - println(uniqueWords.toList) - println(uniqueWords.toList.isSortedBy { (x, y) => x <= y }) + println(uniqueSpeech.toList) + testSorted(uniqueSpeech) - println(set::fromList(words).toList) - println(set::fromList(words).toList.isSortedBy { (x, y) => x <= y }) + println(set::fromList(speech).toList) + testSorted(set::fromList(speech)) // --- + println("") - // around the World / Harder, Better, Faster, Stronger by Daft Punk from Alive 2007 - val alive2007: List[String] = [ + // Around the World / Harder, Better, Faster, Stronger by Daft Punk (Alive 2007) + val lyrics: List[String] = [ "around", "the", "world", "around", "the", "world", "around", "the", "world", "around", "the", "world", "around", "the", "world", "around", "the", "world", @@ -70,16 +81,23 @@ def main() = { "around", "the", "world", "around", "the", "world" ] - val uniqueLyrics = unique(alive2007) + val uniqueLyrics = unique(lyrics) + println(uniqueLyrics.toList) - println(uniqueLyrics.toList.isSortedBy { (a, b) => a <= b }) + testSorted(uniqueLyrics) + + // --- + println("") println("lyrics / speech:") - println(uniqueLyrics.difference(uniqueWords).toList) + println(uniqueLyrics.difference(uniqueSpeech).toList) println("speech / lyrics:") - println(uniqueLyrics.difference(uniqueWords).toList) + println(uniqueSpeech.difference(uniqueLyrics).toList) + + println("speech n lyrics:") + println(uniqueLyrics.intersection(uniqueSpeech).toList) println("speech u lyrics:") - println(uniqueLyrics.union(uniqueWords).toList) + println(uniqueLyrics.union(uniqueSpeech).toList) } diff --git a/libraries/common/map.effekt b/libraries/common/map.effekt index fa0bc7e4f..63457c50a 100644 --- a/libraries/common/map.effekt +++ b/libraries/common/map.effekt @@ -460,9 +460,38 @@ def union[K, V](m1: Map[K, V], m2: Map[K, V]) { combine : (V, V) => V }: Map[K, /// Left-biased: Uses values from `m1` if there are duplicate keys. /// /// O(???) -def union[K, V](m1: Map[K, V], m2: Map[K, V]): Map[K, V] = { - union(m1, m2) { (k, v1, v2) => v1 } -} +def union[K, V](m1: Map[K, V], m2: Map[K, V]): Map[K, V] = + union[K, V](m1, m2) { (k, v1, v2) => v1 } + +/// Construct a new map which combines all elements that are in both `m1` and `m2` using the `combine` function. +/// +/// O(???) +def intersection[K, A, B, C](m1: Map[K, A], m2: Map[K, B]) { combine: (K, A, B) => C }: Map[K, C] = + (m1, m2) match { + case (Tip(), _) => Tip() + case (_, Tip()) => Tip() + case (Bin(_, k, v1, l1, r1), _) => + val (l2, mid, r2) = m2.splitLookup(k) + val left = l1.intersection(l2) { combine } + val right = r1.intersection(r2) { combine } + mid match { + case Some(v2) => link(k, combine(k, v1, v2), left, right) + case None() => link2(left, right) + } + } + +/// Construct a new map which combines all elements that are in both `m1` and `m2` using the `combine` function. +/// +/// O(???) +def intersection[K, A, B, C](m1: Map[K, A], m2: Map[K, B]) { combine: (A, B) => C }: Map[K, C] = + m1.intersection[K, A, B, C](m2) { (k, v1, v2) => combine(v1, v2) } + +/// Construct a new map which combines all elements that are in both `m1` and `m2`. +/// Left-biased: Always uses values from `m1`. +/// +/// O(???) +def intersection[K, A, B](m1: Map[K, A], m2: Map[K, B]): Map[K, A] = + m1.intersection[K, A, B, A](m2) { (k, v1, v2) => v1 } // ------------- // Internal diff --git a/libraries/common/set.effekt b/libraries/common/set.effekt index 1e4da7e85..7cee1d789 100644 --- a/libraries/common/set.effekt +++ b/libraries/common/set.effekt @@ -190,6 +190,17 @@ def union[A](s1: Set[A], s2: Set[A]): Set[A] = { } } +/// Construct a new set which contains only elements which are in both of `s1` and `s2`. +/// +/// O(???) +def intersection[A](s1: Set[A], s2: Set[A]): Set[A] = { + s1.internal::viaInplace { m1 => + s2.internal::via { m2 => + m1.intersection(m2) + } + } +} + // ------------- // Internal