diff --git a/vlib/datatypes/README.md b/vlib/datatypes/README.md index e595c7f3bb..32c9427d6a 100644 --- a/vlib/datatypes/README.md +++ b/vlib/datatypes/README.md @@ -26,5 +26,5 @@ println(stack) - [x] Stack (LIFO) - [x] Queue (FIFO) - [x] Min heap (priority queue) -- [ ] Set +- [x] Set - [ ] ... diff --git a/vlib/datatypes/set.v b/vlib/datatypes/set.v new file mode 100644 index 0000000000..936f97fb9b --- /dev/null +++ b/vlib/datatypes/set.v @@ -0,0 +1,130 @@ +module datatypes + +pub struct Set { +mut: + elements map[T]u8 +} + +// checks the element is exists. +fn (set Set) exists(element T) bool { + return element in set.elements +} + +// adds the element to set, if it is not present already. +fn (mut set Set) add(element T) { + set.elements[element] = 1 +} + +// removes the element from set. +fn (mut set Set) remove(element T) { + set.elements.delete(element) +} + +// pick returns an arbitrary element of set, if set is not empty. +fn (mut set Set) pick() ?T { + for k, _ in set.elements { + return k + } + return error('Set is empty.') +} + +// rest returns the set consisting of all elements except for the arbitrary element. +fn (mut set Set) rest() ?[]T { + element := set.pick()? + return set.elements.keys().filter(it != element) +} + +// pop returns an arbitrary element and deleting it from set. +fn (mut set Set) pop() ?T { + element := set.pick()? + set.elements.delete(element) + return element +} + +// delete all elements of set. +fn (mut set Set) clear() { + set.elements = map[T]u8{} +} + +// checks whether the two given sets are equal (i.e. contain all and only the same elements). +fn (mut l Set) equal(r Set) bool { + if l.elements.len != r.elements.len { + return false + } + for e, _ in r.elements { + if e !in l.elements { + return false + } + } + return true +} + +// checks whether the set is empty. +fn (mut set Set) is_empty() bool { + return set.size() == 0 +} + +// size returns the number of elements in the set. +fn (mut set Set) size() int { + return set.elements.len +} + +// copy returns a copy of all the elements in the set. +fn (mut set Set) copy() Set { + return Set{ + elements: set.elements.clone() + } +} + +// add_all adds the whole `elements` array to the set +fn (mut set Set) add_all(elements []T) { + for element in elements { + set.add(element) + } +} + +// @union returns the union of the two sets. +fn (mut l Set) @union(r Set) Set { + mut set := l + for e, _ in r.elements { + set.add(e) + } + return set +} + +// intersection returns the intersection of sets. +fn (mut l Set) intersection(r Set) Set { + mut set := l + for e, _ in l.elements { + if !r.exists(e) { + set.remove(e) + } + } + for e, _ in r.elements { + if !l.exists(e) { + set.remove(e) + } + } + return set +} + +// difference returns the difference of sets. +fn (mut l Set) difference(r Set) Set { + mut set := l + for e, _ in l.elements { + if r.exists(e) { + set.remove(e) + } + } + return set +} + +// subset returns true if the set `r` is a subset of the set `l`. +fn (mut l Set) subset(r Set) bool { + for e, _ in r.elements { + if e !in l.elements { + return false + } + } + return true +} diff --git a/vlib/datatypes/set_test.v b/vlib/datatypes/set_test.v new file mode 100644 index 0000000000..eef8e1d890 --- /dev/null +++ b/vlib/datatypes/set_test.v @@ -0,0 +1,117 @@ +module datatypes + +fn test_exists() { + mut set := Set{} + set.add('foo') + assert set.exists('foo') + assert set.exists('bar') == false +} + +fn test_remove() { + mut set := Set{} + set.remove('foo') + set.add('foo') + assert set.exists('foo') + set.remove('foo') + assert set.exists('foo') == false +} + +fn test_size() { + mut set := Set{} + set.add('foo') + set.add('foo') + assert set.size() == 1 +} + +fn test_pop() { + mut set := Set{} + set.add('foo') + set.pop() or { return } + assert set.exists('foo') == false +} + +fn test_clear() { + mut set := Set{} + set.add('foo') + set.clear() + assert set.size() == 0 +} + +fn test_rest() { + mut set := Set{} + set.add('foo') + set.add('bar') + array := set.rest() or { return } + assert array.len == 1 +} + +fn test_equal() { + mut first_set := Set{} + mut second_set := Set{} + first_set.add('foo') + assert second_set.equal(first_set) == false + second_set.add('foo') + assert second_set.equal(first_set) +} + +fn test_is_empty() { + mut set := Set{} + assert set.is_empty() + set.add('foo') + assert set.is_empty() == false +} + +fn test_union() { + mut first_set := Set{} + mut second_set := Set{} + first_set.add_all(['b', 'c', 'd']) + second_set.add_all(['a', 'e']) + mut third_set := first_set.@union(second_set) + assert third_set.exists('a') + assert third_set.exists('b') + assert third_set.exists('c') + assert third_set.exists('d') + assert third_set.exists('e') +} + +fn test_intersection() { + mut first_set := Set{} + first_set.add_all(['foo', 'bar', 'baz']) + mut second_set := Set{} + second_set.add_all(['bar', 'baz', 'boo']) + mut third_set := first_set.intersection(second_set) + assert third_set.exists('foo') == false + assert third_set.exists('bar') + assert third_set.exists('baz') + assert third_set.exists('boo') == false +} + +fn test_difference() { + mut first_set := Set{} + mut second_set := Set{} + first_set.add_all(['foo', 'bar', 'baz']) + second_set.add_all(['bar', 'baz', 'boo']) + mut third_set := first_set.difference(second_set) + assert third_set.exists('foo') + assert third_set.exists('bar') == false + assert third_set.exists('baz') == false + assert third_set.exists('boo') == false + first_set.clear() + second_set.clear() + third_set.clear() + first_set.add_all(['bar', 'baz', 'boo']) + second_set.add_all(['foo', 'bar', 'baz']) + third_set = first_set.difference(second_set) + assert third_set.exists('foo') == false + assert third_set.exists('bar') == false + assert third_set.exists('baz') == false + assert third_set.exists('boo') +} + +fn test_subset() { + mut set := Set{} + set.add_all(['a', 'b', 'c']) + mut subset := Set{} + subset.add_all(['b', 'c']) + assert set.subset(subset) +}