Skip to content

Commit

Permalink
Merge pull request #8 from billryan/dev
Browse files Browse the repository at this point in the history
update set
  • Loading branch information
billryan authored Jan 31, 2020
2 parents a68bb9b + 5f67297 commit 5c7796d
Show file tree
Hide file tree
Showing 3 changed files with 190 additions and 60 deletions.
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,36 @@

Maps and slices go a long way in Go, but sometimes you need more. This is a collection of collections that may be useful.

Ported Python and Java collections with love.

## Queue

A [queue](https://en.wikipedia.org/wiki/Queue_\(data_structure\)) is a first-in first-out data structure.

## Set

A [set](https://en.wikipedia.org/wiki/Set_\(computer_science\)) is an unordered collection of unique values typically used for testing membership.

- [x] Add
- [x] AddAll
- [x] Clear
- [x] Contains
- [x] ContainsAll
- [x] Foreach
- [x] Len
- [x] Remove
- [x] RemoveAll
- [] isdisjoint
- [] issubset
- [] issuperset
- [] union
- [] intersection
- [x] Difference
- [] symmetric_difference


## Skip list

A [skip list](https://en.wikipedia.org/wiki/Skip_list) is a data structure that stores nodes in a hierarchy of linked lists. It gives performance similar to binary search trees by using a random number of forward links to skip parts of the list.

## Splay Tree
Expand Down
80 changes: 45 additions & 35 deletions set/set.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,32 +19,6 @@ func New(initial ...interface{}) *Set {
return s
}

// Find the difference between two sets
func (s *Set) Difference(set *Set) *Set {
n := make(map[interface{}]nothing)

for k := range s.hash {
if _, exists := set.hash[k]; !exists {
n[k] = nothing{}
}
}

return &Set{n}
}

// Call f for each item in the set
func (s *Set) Do(f func(interface{})) {
for k := range s.hash {
f(k)
}
}

// Test to see whether or not the element is in the set
func (s *Set) Has(element interface{}) bool {
_, exists := s.hash[element]
return exists
}

// Adds the specified element to this set if it is not already present (optional operation).
func (s *Set) Add(e interface{}) {
s.hash[e] = nothing{}
Expand All @@ -66,32 +40,68 @@ func (s *Set) Clear() {

// Returns true if this set contains the specified element.
func (s *Set) Contains(e interface{}) bool {
_, exists := s.hash[e]
return exists
_, exist := s.hash[e]
return exist
}

// Returns true if this set contains all of the elements of the specified collection.
func (s *Set) ContainsAll(es ...interface{}) bool {
for _, e := range es {
if !s.Contains(e) {
_, exist := s.hash[e]
if !exist {
return false
}
}
return true
}

// Return a new set with elements in the set that are not in the others.
func (s *Set) Difference(set *Set) *Set {
n := make(map[interface{}]nothing)

for k := range s.hash {
if _, exist := set.hash[k]; !exist {
n[k] = nothing{}
}
}

return &Set{n}
}

// Call f for each item in the set
func (s *Set) Foreach(f func(interface{})) {
for k := range s.hash {
f(k)
}
}

// Returns true if this set contains no elements.
func (s *Set) IsEmpty() bool {
return len(s.hash) == 0
}

// Removes the specified element from this set if it is present (optional operation).
func (s *Set) Remove(e interface{}) bool {
exist := s.Contains(e)
_, exist := s.hash[e]
delete(s.hash, e)
return exist
}

// Removes the specified elements from this set if it is present (optional operation).
// Return true if all element exist.
func (s *Set) RemoveAll(es ...interface{}) bool {
existAll := true
for _, e := range es {
_, exist := s.hash[e]
if exist {
delete(s.hash, e)
} else {
existAll = false
}
}
return existAll
}

// Find the intersection of two sets
func (s *Set) Intersection(set *Set) *Set {
n := make(map[interface{}]nothing)
Expand All @@ -105,14 +115,14 @@ func (s *Set) Intersection(set *Set) *Set {
return &Set{n}
}

// Returns the number of elements in this set (its cardinality).
func (s *Set) Size() int {
// Return the number of elements in set s (cardinality of s).
func (s *Set) Len() int {
return len(s.hash)
}

// Returns an slice containing all of the elements in this set.
func (s *Set) ToSlice() []interface{} {
slice := make([]interface{}, s.Size())
slice := make([]interface{}, s.Len())
for e := range s.hash {
slice = append(slice, e)
}
Expand All @@ -121,12 +131,12 @@ func (s *Set) ToSlice() []interface{} {

// Test whether or not this set is a proper subset of "set"
func (s *Set) ProperSubsetOf(set *Set) bool {
return s.SubsetOf(set) && s.Size() < set.Size()
return s.SubsetOf(set) && s.Len() < set.Len()
}

// Test whether or not this set is a subset of "set"
func (s *Set) SubsetOf(set *Set) bool {
if s.Size() > set.Size() {
if s.Len() > set.Len() {
return false
}
for k := range s.hash {
Expand Down
147 changes: 122 additions & 25 deletions set/set_test.go
Original file line number Diff line number Diff line change
@@ -1,67 +1,164 @@
package set

import (
"fmt"
"testing"
)

func TestNew(t *testing.T) {
s := New()
if s.Len() != 0 {
t.Error("Length of empty init set should be 0")
}

s = New(1, 4, 8)
if s.Len() != 3 {
t.Error("Length should be 3")
}
}

func TestSet_Add(t *testing.T) {
s := New()
s.Add("k1")

if !s.Contains("k1") {
t.Error("Set should contain 'k1'")
}
}

func TestSet_AddAll(t *testing.T) {
s := New()
s.AddAll("k1", "k2")
if s.Len() != 2 {
t.Error("Length should be 2")
}
}

func TestSet_Clear(t *testing.T) {
s := New(1, 2, 4, 8)
s.Clear()
if s.Len() != 0 {
t.Error("Length should be 0 after clear()")
}
}

func TestSet_Contains(t *testing.T) {
s := New(1, 2)
if s.Contains(0) {
t.Error("Set should not contain 0")
}

if !s.Contains(1) {
t.Error("Set should contain 1")
}
}

func TestSet_ContainsAll(t *testing.T) {
s := New(1, 2, 4)
if !s.ContainsAll(1, 2) {
t.Error("Set should contain 1 and 2")
}

if s.ContainsAll(1, 3) {
t.Error("Set should not contain 1 and 3")
}
}

func TestSet_Difference(t *testing.T) {
s1 := New(1, 2, 4)
s2 := New(4, 8)
s3 := s1.Difference(s2)
if s3.Contains(4) || s3.Contains(8) {
t.Error("Set should not contain 4 or 8")
}

if !s3.ContainsAll(1, 2) {
t.Error("Set should contain 1 and 2")
}
}

func TestSet_Foreach(t *testing.T) {
s := New(1, 2, 3)
f := func(x interface{}) { fmt.Printf("type of x is %T and value is %v\n", x, x) }
s.Foreach(f)
}

func TestSet_Len(t *testing.T) {
s := New()
if s.Len() != 0 {
t.Error("Length should be 0")
}

s.AddAll(1, 2, 4)
if s.Len() != 3 {
t.Error("Length should be 3")
}
}

func TestSet_Remove(t *testing.T) {
s := New()
s.Remove(2)
if s.Len() != 0 {
t.Error("Length should be 0")
}

s.AddAll(1, 2, 4)
s.Remove(2)
if s.Contains(2) {
t.Error("Set s should not contain 2")
}
}

func TestSet_RemoveAll(t *testing.T) {
s := New(1, 2, 4)
exist := s.RemoveAll(1, 2)
if !exist {
t.Error("Set s should contain 1 and 2 before RemoveAll(1, 2)")
}

if !s.Contains(4) {
t.Error("Set s should contain 4")
}
}

func Test(t *testing.T) {
s := New()

s.Add(5)

if s.Size() != 1 {
if s.Len() != 1 {
t.Errorf("Length should be 1")
}

if !s.Has(5) {
t.Errorf("Membership test failed")
}

s.Remove(5)

if s.Size() != 0 {
if s.Len() != 0 {
t.Errorf("Length should be 0")
}

if s.Has(5) {
t.Errorf("The set should be empty")
}

// Difference
s1 := New(1, 2, 3, 4, 5, 6)
s2 := New(4, 5, 6)
s3 := s1.Difference(s2)

if s3.Size() != 3 {
if s3.Len() != 3 {
t.Errorf("Length should be 3")
}

if !(s3.Has(1) && s3.Has(2) && s3.Has(3)) {
t.Errorf("Set should only contain 1, 2, 3")
}

// Intersection
s3 = s1.Intersection(s2)
if s3.Size() != 3 {
if s3.Len() != 3 {
t.Errorf("Length should be 3 after intersection")
}

if !(s3.Has(4) && s3.Has(5) && s3.Has(6)) {
t.Errorf("Set should contain 4, 5, 6")
}

// Union
s4 := New(7, 8, 9)
s3 = s2.Union(s4)

if s3.Size() != 6 {
if s3.Len() != 6 {
t.Errorf("Length should be 6 after union")
}

if !(s3.Has(7)) {
t.Errorf("Set should contain 4, 5, 6, 7, 8, 9")
}

// Subset
if !s1.SubsetOf(s1) {
t.Errorf("set should be a subset of itself")
Expand Down

0 comments on commit 5c7796d

Please sign in to comment.