From 5f67297bfe54a1c3f7cb30dbf11d741c3b9d5878 Mon Sep 17 00:00:00 2001 From: billryan Date: Fri, 31 Jan 2020 19:18:57 +0800 Subject: [PATCH] update set --- README.md | 23 ++++++++ set/set.go | 80 ++++++++++++++------------ set/set_test.go | 147 ++++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 190 insertions(+), 60 deletions(-) diff --git a/README.md b/README.md index 2b7202f..22e472c 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/set/set.go b/set/set.go index 209de30..9600b16 100755 --- a/set/set.go +++ b/set/set.go @@ -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{} @@ -66,20 +40,41 @@ 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 @@ -87,11 +82,26 @@ func (s *Set) IsEmpty() bool { // 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) @@ -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) } @@ -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 { diff --git a/set/set_test.go b/set/set_test.go index f603f0a..89e5063 100644 --- a/set/set_test.go +++ b/set/set_test.go @@ -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")