From 549ece11005b54a6d4b07e4ecdefdeb944040de8 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 22 Jun 2016 04:53:38 +0200 Subject: [PATCH] - iterator implementation - tests for arraylist enumerable operations --- containers/iterator.go | 3 + lists/arraylist/arraylist.go | 58 +++++++------- lists/arraylist/arraylist_test.go | 126 ++++++++++++++++++++++++++++++ 3 files changed, 158 insertions(+), 29 deletions(-) diff --git a/containers/iterator.go b/containers/iterator.go index 513a04f..0dcb829 100644 --- a/containers/iterator.go +++ b/containers/iterator.go @@ -29,7 +29,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package containers type Iterator interface { + // Moves the iterator to the next element and returns true if there was a next element in the container. Next() bool + // Returns the current element's value. Value() interface{} + // Returns the current element's index(key). Index() interface{} } diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index bdcf1ad..ff3f51d 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -49,28 +49,6 @@ type List struct { size int } -type Iterator struct { - list *List - current int -} - -func (list *List) Iterator() Iterator { - return Iterator{list: list, current: -1} -} - -func (iterator *Iterator) Next() bool { - iterator.current += 1 - return iterator.list.withinRange(iterator.current) -} - -func (iterator *Iterator) Value() interface{} { - return iterator.list.elements[iterator.current] -} - -func (iterator *Iterator) Index() interface{} { - return iterator.list.elements[iterator.current] -} - const ( GROWTH_FACTOR = float32(2.0) // growth by 100% SHRINK_FACTOR = float32(0.25) // shrink when size is 25% of capacity (0 means never shrink) @@ -109,7 +87,7 @@ func (list *List) Remove(index int) { } list.elements[index] = nil // cleanup reference - copy(list.elements[index:], list.elements[index + 1:list.size]) // shift to the left by one (slow operation, need ways to optimize this) + copy(list.elements[index:], list.elements[index+1:list.size]) // shift to the left by one (slow operation, need ways to optimize this) list.size -= 1 list.shrink() @@ -191,12 +169,12 @@ func (list *List) Insert(index int, values ...interface{}) { list.growBy(l) list.size += l // Shift old to right - for i := list.size - 1; i >= index + l; i-- { - list.elements[i] = list.elements[i - l] + for i := list.size - 1; i >= index+l; i-- { + list.elements[i] = list.elements[i-l] } // Insert new for i, value := range values { - list.elements[index + i] = value + list.elements[index+i] = value } } @@ -251,6 +229,28 @@ func (list *List) Find(f func(index interface{}, value interface{}) bool) (index return nil, nil } +type Iterator struct { + list *List + current int +} + +func (list *List) Iterator() Iterator { + return Iterator{list: list, current: -1} +} + +func (iterator *Iterator) Next() bool { + iterator.current += 1 + return iterator.list.withinRange(iterator.current) +} + +func (iterator *Iterator) Value() interface{} { + return iterator.list.elements[iterator.current] +} + +func (iterator *Iterator) Index() interface{} { + return iterator.current +} + func (list *List) String() string { str := "ArrayList\n" values := []string{} @@ -276,8 +276,8 @@ func (list *List) resize(cap int) { func (list *List) growBy(n int) { // When capacity is reached, grow by a factor of GROWTH_FACTOR and add number of elements currentCapacity := cap(list.elements) - if list.size + n >= currentCapacity { - newCapacity := int(GROWTH_FACTOR * float32(currentCapacity + n)) + if list.size+n >= currentCapacity { + newCapacity := int(GROWTH_FACTOR * float32(currentCapacity+n)) list.resize(newCapacity) } } @@ -289,7 +289,7 @@ func (list *List) shrink() { } // Shrink when size is at SHRINK_FACTOR * capacity currentCapacity := cap(list.elements) - if list.size <= int(float32(currentCapacity) * SHRINK_FACTOR) { + if list.size <= int(float32(currentCapacity)*SHRINK_FACTOR) { list.resize(list.size) } } diff --git a/lists/arraylist/arraylist_test.go b/lists/arraylist/arraylist_test.go index ab07f67..ac25687 100644 --- a/lists/arraylist/arraylist_test.go +++ b/lists/arraylist/arraylist_test.go @@ -136,6 +136,132 @@ func TestArrayList(t *testing.T) { } +func TestArrayListEnumerableAndIterator(t *testing.T) { + list := New() + list.Add("a", "b", "c") + + // Each + list.Each(func(index interface{}, value interface{}) { + switch index { + case 0: + if actualValue, expectedValue := value, "a"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 1: + if actualValue, expectedValue := value, "b"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 2: + if actualValue, expectedValue := value, "c"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + }) + + // Map + mappedList := list.Map(func(index interface{}, value interface{}) interface{} { + return "mapped: " + value.(string) + }).(*List) + if actualValue, _ := mappedList.Get(0); actualValue != "mapped: a" { + t.Errorf("Got %v expected %v", actualValue, "mapped: a") + } + if actualValue, _ := mappedList.Get(1); actualValue != "mapped: b" { + t.Errorf("Got %v expected %v", actualValue, "mapped: b") + } + if actualValue, _ := mappedList.Get(2); actualValue != "mapped: c" { + t.Errorf("Got %v expected %v", actualValue, "mapped: c") + } + if mappedList.Size() != 3 { + t.Errorf("Got %v expected %v", mappedList.Size(), 3) + } + + // Select + selectedList := list.Select(func(index interface{}, value interface{}) bool { + return value.(string) >= "a" && value.(string) <= "b" + }).(*List) + if actualValue, _ := selectedList.Get(0); actualValue != "a" { + t.Errorf("Got %v expected %v", actualValue, "value: a") + } + if actualValue, _ := selectedList.Get(1); actualValue != "b" { + t.Errorf("Got %v expected %v", actualValue, "value: b") + } + if selectedList.Size() != 2 { + t.Errorf("Got %v expected %v", selectedList.Size(), 3) + } + + // Any + any := list.Any(func(index interface{}, value interface{}) bool { + return value.(string) == "c" + }) + if any != true { + t.Errorf("Got %v expected %v", any, true) + } + any = list.Any(func(index interface{}, value interface{}) bool { + return value.(string) == "x" + }) + if any != false { + t.Errorf("Got %v expected %v", any, false) + } + + // All + all := list.All(func(index interface{}, value interface{}) bool { + return value.(string) >= "a" && value.(string) <= "c" + }) + if all != true { + t.Errorf("Got %v expected %v", all, true) + } + all = list.All(func(index interface{}, value interface{}) bool { + return value.(string) >= "a" && value.(string) <= "b" + }) + if all != false { + t.Errorf("Got %v expected %v", all, false) + } + + // Find + foundIndex, foundValue := list.Find(func(index interface{}, value interface{}) bool { + return value.(string) == "c" + }) + if foundValue != "c" || foundIndex != 2 { + t.Errorf("Got %v at %v expected %v at %v", foundValue, foundIndex, "c", 2) + } + foundIndex, foundValue = list.Find(func(index interface{}, value interface{}) bool { + return value.(string) == "x" + }) + if foundValue != nil || foundIndex != nil { + t.Errorf("Got %v at %v expected %v at %v", foundValue, foundIndex, nil, nil) + } + + // Iterator + it := list.Iterator() + for it.Next() { + index := it.Index() + value := it.Value() + switch index { + case 0: + if actualValue, expectedValue := value, "a"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 1: + if actualValue, expectedValue := value, "b"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 2: + if actualValue, expectedValue := value, "c"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + } + list.Clear() + it = list.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty list") + } +} + func BenchmarkArrayList(b *testing.B) { for i := 0; i < b.N; i++ { list := New()