Added logical set operations to TSet

This commit is contained in:
Felix Krause
2014-06-25 21:57:06 +02:00
parent b090b7ea4d
commit bdd3b6c612
2 changed files with 130 additions and 0 deletions

View File

@@ -112,6 +112,10 @@ proc incl*[A](s: var TSet[A], key: A) =
## includes an element `key` in `s`.
inclImpl()
proc incl*[A](s: var TSet[A], other: TSet[A]) =
## includes everything in `other` in `s`
for item in other: incl(s, item)
proc excl*[A](s: var TSet[A], key: A) =
## excludes `key` from the set `s`.
var index = rawGet(s, key)
@@ -119,6 +123,10 @@ proc excl*[A](s: var TSet[A], key: A) =
s.data[index].slot = seDeleted
dec(s.counter)
proc excl*[A](s: var TSet[A], other: TSet[A]) =
## excludes everything in `other` from `s`.
for item in other: excl(s, item)
proc containsOrIncl*[A](s: var TSet[A], key: A): bool =
## returns true if `s` contains `key`, otherwise `key` is included in `s`
## and false is returned.
@@ -147,6 +155,43 @@ proc `$`*[A](s: TSet[A]): string =
## The `$` operator for hash sets.
dollarImpl()
proc union*[A](s1, s2: TSet[A]): TSet[A] =
## returns a new set of all items that are contained in at
## least one of `l` and `r`
result = s1
incl(result, s2)
proc intersection*[A](s1, s2: TSet[A]): TSet[A] =
## returns a new set of all items that are contained in both `l` and `r`
result = initSet[A](min(s1.data.len, s2.data.len))
for item in s1:
if item in s2: incl(result, item)
proc symmetricDifference*[A](s1, s2: TSet[A]): TSet[A] =
## returns a new set of all items that are contained in either
## `l` or `r`, but not both
result = s1
for item in s2:
if containsOrIncl(result, item): excl(result, item)
proc `or`*[A](s1, s2: TSet[A]): TSet[A] {.inline.} =
## alias for `union`
result = union(s1, s2)
proc `and`*[A](s1, s2: TSet[A]): TSet[A] {.inline.} =
## alias for `intersection`
result = intersection(s1, s2)
proc `xor`*[A](s1, s2: TSet[A]): TSet[A] {.inline.} =
## alias for `symmetricDifference`
result = symmetricDifference(s1, s2)
proc disjoint*[A](s1, s2: TSet[A]): bool =
## returns true iff `l` and `r` have no items in common
for item in s1:
if item in s2: return false
return true
# ------------------------------ ordered set ------------------------------
type
@@ -211,6 +256,10 @@ proc incl*[A](s: var TOrderedSet[A], key: A) =
## includes an element `key` in `s`.
inclImpl()
proc incl*[A](s: var TSet[A], other: TOrderedSet[A]) =
## includes everything in `other` in `s`
for item in other: incl(s, item)
proc containsOrIncl*[A](s: var TOrderedSet[A], key: A): bool =
## returns true if `s` contains `key`, otherwise `key` is included in `s`
## and false is returned.

81
tests/sets/tsets3.nim Normal file
View File

@@ -0,0 +1,81 @@
include sets
let
s1: TSet[int] = toSet([1, 2, 4, 8, 16])
s2: TSet[int] = toSet([1, 2, 3, 5, 8])
s3: TSet[int] = toSet([3, 5, 7])
block union:
let
s1_s2 = union(s1, s2)
s1_s3 = s1 or s3
s2_s3 = s2 or s3
assert s1_s2.len == 7
assert s1_s3.len == 8
assert s2_s3.len == 6
for i in s1:
assert i in s1_s2
assert i in s1_s3
for i in s2:
assert i in s1_s2
assert i in s2_s3
for i in s3:
assert i in s1_s3
assert i in s2_s3
assert((s1 or s1) == s1)
assert((s2 or s1) == s1_s2)
block intersection:
let
s1_s2 = intersection(s1, s2)
s1_s3 = intersection(s1, s3)
s2_s3 = s2 and s3
assert s1_s2.len == 3
assert s1_s3.len == 0
assert s2_s3.len == 2
for i in s1_s2:
assert i in s1
assert i in s2
for i in s1_s3:
assert i in s1
assert i in s3
for i in s2_s3:
assert i in s2
assert i in s3
assert((s2 and s2) == s2)
assert((s3 and s2) == s2_s3)
block symmetricDifference:
let
s1_s2 = symmetricDifference(s1, s2)
s1_s3 = s1 xor s3
s2_s3 = s2 xor s3
assert s1_s2.len == 4
assert s1_s3.len == 8
assert s2_s3.len == 4
for i in s1:
assert i in s1_s2 xor i in s2
assert i in s1_s3 xor i in s3
for i in s2:
assert i in s1_s2 xor i in s1
assert i in s2_s3 xor i in s3
for i in s3:
assert i in s1_s3 xor i in s1
assert i in s2_s3 xor i in s2
assert((s3 xor s3) == initSet[int]())
assert((s3 xor s1) == s1_s3)
block disjoint:
assert(not disjoint(s1, s2))
assert disjoint(s1, s3)
assert(not disjoint(s2, s3))
assert(not disjoint(s2, s2))