diff --git a/README.md b/README.md index ad968b9..a491abb 100644 --- a/README.md +++ b/README.md @@ -649,8 +649,9 @@ All ordered containers have stateful iterators. Typically an iterator is obtaine #### IteratorWithIndex -A [iterator](#iterator) whose elements are referenced by an index. Typical usage: +An [iterator](#iterator) whose elements are referenced by an index. +Typical usage: ```go it := list.Iterator() for it.Next() { @@ -659,44 +660,89 @@ for it.Next() { } ``` +Other usages: +```go +if it.First() { + firstIndex, firstValue := it.Index(), it.Value() + ... +} +``` + +```go +for it.Begin(); it.Next(); { + ... +} +``` + #### IteratorWithKey -A [iterator](#iterator) whose elements are referenced by a key. Typical usage: +An [iterator](#iterator) whose elements are referenced by a key. +Typical usage: ```go -it := map.Iterator() +it := tree.Iterator() for it.Next() { key, value := it.Key(), it.Value() ... } ``` -#### ReverseIteratorWithIndex - -A [iterator](#iterator) whose elements are referenced by an index. Typical usage: +Other usages: +```go +if it.First() { + firstKey, firstValue := it.Key(), it.Value() + ... +} +``` +```go +for it.Begin(); it.Next(); { + ... +} +``` + +#### ReverseIteratorWithIndex + +An [iterator](#iterator) whose elements are referenced by an index. Provides all functions as [IteratorWithIndex](#iteratorwithindex), but can also be used for reverse iteration. + +Typical usage of iteration in reverse: ```go it := list.Iterator() -for it.Next() { /* Move to end */ } -for it.Prev() { +for it.End(); it.Prev(); { index, value := it.Index(), it.Value() ... } ``` +Other usages: +```go +if it.Last() { + lastIndex, lastValue := it.Index(), it.Value() + ... +} +``` + #### ReverseIteratorWithKey -A [iterator](#iterator) whose elements are referenced by a key. Typical usage: +An [iterator](#iterator) whose elements are referenced by a key. Provides all functions as [IteratorWithKey](#iteratorwithkey), but can also be used for reverse iteration. +Typical usage of iteration in reverse: ```go -it := map.Iterator() -for it.Next() { /* Move to end */ } -for it.Prev() { +it := tree.Iterator() +for it.End(); it.Prev(); { key, value := it.Key(), it.Value() ... } ``` +Other usages: +```go +if it.Last() { + lastKey, lastValue := it.Key(), it.Value() + ... +} +``` + ### Enumerable Enumerable functions for ordered containers that implement [EnumerableWithIndex](#enumerablewithindex) or [EnumerableWithKey](#enumerablewithkey) interfaces. diff --git a/containers/iterator.go b/containers/iterator.go index c1a7c54..5692982 100644 --- a/containers/iterator.go +++ b/containers/iterator.go @@ -30,56 +30,102 @@ package containers type IteratorWithIndex interface { // Next moves the iterator to the next element and returns true if there was a next element in the container. // If Next() returns true, then next element's index and value can be retrieved by Index() and Value(). + // If Next() was called for the first time, then it will point the iterator to the first element if it exists. // Modifies the state of the iterator. Next() bool + // Value returns the current element's value. // Does not modify the state of the iterator. Value() interface{} + // Index returns the current element's index. // Does not modify the state of the iterator. Index() int + + // Begin resets the iterator to its initial state (one-before-first) + // Call Next() to fetch the first element if any. + Begin() + + // First moves the iterator to the first element and returns true if there was a first element in the container. + // If First() returns true, then first element's index and value can be retrieved by Index() and Value(). + // Modifies the state of the iterator. + First() bool } // IteratorWithKey is a stateful iterator for ordered containers whose elements are key value pairs. type IteratorWithKey interface { // Next moves the iterator to the next element and returns true if there was a next element in the container. // If Next() returns true, then next element's key and value can be retrieved by Key() and Value(). + // If Next() was called for the first time, then it will point the iterator to the first element if it exists. // Modifies the state of the iterator. Next() bool + // Value returns the current element's value. // Does not modify the state of the iterator. Value() interface{} + // Key returns the current element's key. // Does not modify the state of the iterator. Key() interface{} + + // Begin resets the iterator to its initial state (one-before-first) + // Call Next() to fetch the first element if any. + Begin() + + // First moves the iterator to the first element and returns true if there was a first element in the container. + // If First() returns true, then first element's key and value can be retrieved by Key() and Value(). + // Modifies the state of the iterator. + First() bool } // ReverseIteratorWithIndex is stateful iterator for ordered containers whose values can be fetched by an index. // -// Essentially it is the same as IteratorWithIndex, but provides additional Prev() function to enable traversal in reverse. +// Essentially it is the same as IteratorWithIndex, but provides additional: +// +// Prev() function to enable traversal in reverse +// +// Last() function to move the iterator to the last element. +// +// End() function to move the iterator past the last element (one-past-the-end). type ReverseIteratorWithIndex interface { // Prev moves the iterator to the previous element and returns true if there was a previous element in the container. // If Prev() returns true, then previous element's index and value can be retrieved by Index() and Value(). // Modifies the state of the iterator. Prev() bool + // End moves the iterator past the last element (one-past-the-end). + // Call Prev() to fetch the last element if any. + End() + + // Last moves the iterator to the last element and returns true if there was a last element in the container. + // If Last() returns true, then last element's index and value can be retrieved by Index() and Value(). + // Modifies the state of the iterator. + Last() bool + IteratorWithIndex - // Next() bool - // Value() interface{} - // Index() int } // ReverseIteratorWithKey is a stateful iterator for ordered containers whose elements are key value pairs. // -// Essentially it is the same as IteratorWithKey, but provides additional Prev() function to enable traversal in reverse. +// Essentially it is the same as IteratorWithKey, but provides additional: +// +// Prev() function to enable traversal in reverse +// +// Last() function to move the iterator to the last element. type ReverseIteratorWithKey interface { // Prev moves the iterator to the previous element and returns true if there was a previous element in the container. - // If Prev() returns true, then previous element's index and value can be retrieved by Key() and Value(). + // If Prev() returns true, then previous element's key and value can be retrieved by Key() and Value(). // Modifies the state of the iterator. Prev() bool + // End moves the iterator past the last element (one-past-the-end). + // Call Prev() to fetch the last element if any. + End() + + // Last moves the iterator to the last element and returns true if there was a last element in the container. + // If Last() returns true, then last element's key and value can be retrieved by Key() and Value(). + // Modifies the state of the iterator. + Last() bool + IteratorWithKey - // Next() bool - // Value() interface{} - // Key() interface{} } diff --git a/examples/iteratorwithindex.go b/examples/iteratorwithindex.go new file mode 100644 index 0000000..8edfe30 --- /dev/null +++ b/examples/iteratorwithindex.go @@ -0,0 +1,73 @@ +/* +Copyright (c) 2015, Emir Pasic +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package examples + +import ( + "fmt" + "github.com/emirpasic/gods/sets/treeset" +) + +// IteratorWithIndexExample to demonstrate basic usage of IteratorWithIndex +func IteratorWithIndexExample() { + set := treeset.NewWithStringComparator() + set.Add("a", "b", "c") + it := set.Iterator() + + fmt.Print("\nForward iteration\n") + for it.Next() { + index, value := it.Index(), it.Value() + fmt.Print("[", index, ":", value, "]") // [0:a][1:b][2:c] + } + + fmt.Print("\nForward iteration (again)\n") + for it.Begin(); it.Next(); { + index, value := it.Index(), it.Value() + fmt.Print("[", index, ":", value, "]") // [0:a][1:b][2:c] + } + + fmt.Print("\nBackward iteration\n") + for it.Prev() { + index, value := it.Index(), it.Value() + fmt.Print("[", index, ":", value, "]") // [2:c][1:b][0:a] + } + + fmt.Print("\nBackward iteration (again)\n") + for it.End(); it.Prev(); { + index, value := it.Index(), it.Value() + fmt.Print("[", index, ":", value, "]") // [2:c][1:b][0:a] + } + + if it.First() { + fmt.Print("\nFirst index: ", it.Index()) // First index: 0 + fmt.Print("\nFirst value: ", it.Value()) // First value: a + } + + if it.Last() { + fmt.Print("\nLast index: ", it.Index()) // Last index: 3 + fmt.Print("\nLast value: ", it.Value()) // Last value: c + } +} diff --git a/examples/iteratorwithkey.go b/examples/iteratorwithkey.go new file mode 100644 index 0000000..51716a2 --- /dev/null +++ b/examples/iteratorwithkey.go @@ -0,0 +1,75 @@ +/* +Copyright (c) 2015, Emir Pasic +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package examples + +import ( + "fmt" + "github.com/emirpasic/gods/maps/treemap" +) + +// IteratorWithKeyExample to demonstrate basic usage of IteratorWithKey +func IteratorWithKeyExample() { + m := treemap.NewWithIntComparator() + m.Put(1, "a") + m.Put(2, "b") + m.Put(3, "a") + it := m.Iterator() + + fmt.Print("\nForward iteration\n") + for it.Next() { + key, value := it.Key(), it.Value() + fmt.Print("[", key, ":", value, "]") // [0:a][1:b][2:c] + } + + fmt.Print("\nForward iteration (again)\n") + for it.Begin(); it.Next(); { + key, value := it.Key(), it.Value() + fmt.Print("[", key, ":", value, "]") // [0:a][1:b][2:c] + } + + fmt.Print("\nBackward iteration\n") + for it.Prev() { + key, value := it.Key(), it.Value() + fmt.Print("[", key, ":", value, "]") // [2:c][1:b][0:a] + } + + fmt.Print("\nBackward iteration (again)\n") + for it.End(); it.Prev(); { + key, value := it.Key(), it.Value() + fmt.Print("[", key, ":", value, "]") // [2:c][1:b][0:a] + } + + if it.First() { + fmt.Print("\nFirst key: ", it.Key()) // First key: 0 + fmt.Print("\nFirst value: ", it.Value()) // First value: a + } + + if it.Last() { + fmt.Print("\nLast key: ", it.Key()) // Last key: 3 + fmt.Print("\nLast value: ", it.Value()) // Last value: c + } +} diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index c08d928..4e44d4a 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -193,6 +193,7 @@ func (list *List) Iterator() Iterator { // Next moves the iterator to the next element and returns true if there was a next element in the container. // If Next() returns true, then next element's index and value can be retrieved by Index() and Value(). +// If Next() was called for the first time, then it will point the iterator to the first element if it exists. // Modifies the state of the iterator. func (iterator *Iterator) Next() bool { if iterator.index < iterator.list.size { @@ -223,6 +224,34 @@ func (iterator *Iterator) Index() int { return iterator.index } +// Begin resets the iterator to its initial state (one-before-first) +// Call Next() to fetch the first element if any. +func (iterator *Iterator) Begin() { + iterator.index = -1 +} + +// End moves the iterator past the last element (one-past-the-end). +// Call Prev() to fetch the last element if any. +func (iterator *Iterator) End() { + iterator.index = iterator.list.size +} + +// First moves the iterator to the first element and returns true if there was a first element in the container. +// If First() returns true, then first element's index and value can be retrieved by Index() and Value(). +// Modifies the state of the iterator. +func (iterator *Iterator) First() bool { + iterator.Begin() + return iterator.Next() +} + +// Last moves the iterator to the last element and returns true if there was a last element in the container. +// If Last() returns true, then last element's index and value can be retrieved by Index() and Value(). +// Modifies the state of the iterator. +func (iterator *Iterator) Last() bool { + iterator.End() + return iterator.Prev() +} + // Each calls the given function once for each element, passing that element's index and value. func (list *List) Each(f func(index int, value interface{})) { iterator := list.Iterator() diff --git a/lists/arraylist/arraylist_test.go b/lists/arraylist/arraylist_test.go index 9de67da..daf8a16 100644 --- a/lists/arraylist/arraylist_test.go +++ b/lists/arraylist/arraylist_test.go @@ -379,6 +379,75 @@ func TestListIteratorPrev(t *testing.T) { } } +func TestListIteratorBegin(t *testing.T) { + list := New() + it := list.Iterator() + it.Begin() + list.Add("a", "b", "c") + for it.Next() { + } + it.Begin() + it.Next() + if index, value := it.Index(), it.Value(); index != 0 || value != "a" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "a") + } +} + +func TestListIteratorEnd(t *testing.T) { + list := New() + it := list.Iterator() + + if index := it.Index(); index != -1 { + t.Errorf("Got %v expected %v", index, -1) + } + + it.End() + if index := it.Index(); index != 0 { + t.Errorf("Got %v expected %v", index, 0) + } + + list.Add("a", "b", "c") + it.End() + if index := it.Index(); index != list.Size() { + t.Errorf("Got %v expected %v", index, list.Size()) + } + + it.Prev() + if index, value := it.Index(), it.Value(); index != list.Size()-1 || value != "c" { + t.Errorf("Got %v,%v expected %v,%v", index, value, list.Size()-1, "c") + } +} + +func TestListIteratorFirst(t *testing.T) { + list := New() + it := list.Iterator() + if actualValue, expectedValue := it.First(), false; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + list.Add("a", "b", "c") + if actualValue, expectedValue := it.First(), true; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if index, value := it.Index(), it.Value(); index != 0 || value != "a" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "a") + } +} + +func TestListIteratorLast(t *testing.T) { + list := New() + it := list.Iterator() + if actualValue, expectedValue := it.Last(), false; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + list.Add("a", "b", "c") + if actualValue, expectedValue := it.Last(), true; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if index, value := it.Index(), it.Value(); index != 2 || value != "c" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "c") + } +} + func BenchmarkList(b *testing.B) { for i := 0; i < b.N; i++ { list := New() diff --git a/lists/doublylinkedlist/doublylinkedlist.go b/lists/doublylinkedlist/doublylinkedlist.go index cb7bdfc..184db76 100644 --- a/lists/doublylinkedlist/doublylinkedlist.go +++ b/lists/doublylinkedlist/doublylinkedlist.go @@ -314,6 +314,7 @@ func (list *List) Iterator() Iterator { // Next moves the iterator to the next element and returns true if there was a next element in the container. // If Next() returns true, then next element's index and value can be retrieved by Index() and Value(). +// If Next() was called for the first time, then it will point the iterator to the first element if it exists. // Modifies the state of the iterator. func (iterator *Iterator) Next() bool { if iterator.index < iterator.list.size { @@ -362,6 +363,36 @@ func (iterator *Iterator) Index() int { return iterator.index } +// Begin resets the iterator to its initial state (one-before-first) +// Call Next() to fetch the first element if any. +func (iterator *Iterator) Begin() { + iterator.index = -1 + iterator.element = nil +} + +// End moves the iterator past the last element (one-past-the-end). +// Call Prev() to fetch the last element if any. +func (iterator *Iterator) End() { + iterator.index = iterator.list.size + iterator.element = iterator.list.last +} + +// First moves the iterator to the first element and returns true if there was a first element in the container. +// If First() returns true, then first element's index and value can be retrieved by Index() and Value(). +// Modifies the state of the iterator. +func (iterator *Iterator) First() bool { + iterator.Begin() + return iterator.Next() +} + +// Last moves the iterator to the last element and returns true if there was a last element in the container. +// If Last() returns true, then last element's index and value can be retrieved by Index() and Value(). +// Modifies the state of the iterator. +func (iterator *Iterator) Last() bool { + iterator.End() + return iterator.Prev() +} + // Each calls the given function once for each element, passing that element's index and value. func (list *List) Each(f func(index int, value interface{})) { iterator := list.Iterator() diff --git a/lists/doublylinkedlist/doublylinkedlist_test.go b/lists/doublylinkedlist/doublylinkedlist_test.go index 1ff73b6..8cd9e96 100644 --- a/lists/doublylinkedlist/doublylinkedlist_test.go +++ b/lists/doublylinkedlist/doublylinkedlist_test.go @@ -379,6 +379,75 @@ func TestListIteratorPrev(t *testing.T) { } } +func TestListIteratorBegin(t *testing.T) { + list := New() + it := list.Iterator() + it.Begin() + list.Add("a", "b", "c") + for it.Next() { + } + it.Begin() + it.Next() + if index, value := it.Index(), it.Value(); index != 0 || value != "a" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "a") + } +} + +func TestListIteratorEnd(t *testing.T) { + list := New() + it := list.Iterator() + + if index := it.Index(); index != -1 { + t.Errorf("Got %v expected %v", index, -1) + } + + it.End() + if index := it.Index(); index != 0 { + t.Errorf("Got %v expected %v", index, 0) + } + + list.Add("a", "b", "c") + it.End() + if index := it.Index(); index != list.Size() { + t.Errorf("Got %v expected %v", index, list.Size()) + } + + it.Prev() + if index, value := it.Index(), it.Value(); index != list.Size()-1 || value != "c" { + t.Errorf("Got %v,%v expected %v,%v", index, value, list.Size()-1, "c") + } +} + +func TestListIteratorFirst(t *testing.T) { + list := New() + it := list.Iterator() + if actualValue, expectedValue := it.First(), false; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + list.Add("a", "b", "c") + if actualValue, expectedValue := it.First(), true; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if index, value := it.Index(), it.Value(); index != 0 || value != "a" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "a") + } +} + +func TestListIteratorLast(t *testing.T) { + list := New() + it := list.Iterator() + if actualValue, expectedValue := it.Last(), false; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + list.Add("a", "b", "c") + if actualValue, expectedValue := it.Last(), true; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if index, value := it.Index(), it.Value(); index != 2 || value != "c" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "c") + } +} + func BenchmarkList(b *testing.B) { for i := 0; i < b.N; i++ { list := New() diff --git a/lists/singlylinkedlist/singlylinkedlist.go b/lists/singlylinkedlist/singlylinkedlist.go index f65f728..41db255 100644 --- a/lists/singlylinkedlist/singlylinkedlist.go +++ b/lists/singlylinkedlist/singlylinkedlist.go @@ -286,6 +286,7 @@ func (list *List) Iterator() Iterator { // Next moves the iterator to the next element and returns true if there was a next element in the container. // If Next() returns true, then next element's index and value can be retrieved by Index() and Value(). +// If Next() was called for the first time, then it will point the iterator to the first element if it exists. // Modifies the state of the iterator. func (iterator *Iterator) Next() bool { if iterator.index < iterator.list.size { @@ -315,6 +316,21 @@ func (iterator *Iterator) Index() int { return iterator.index } +// Begin resets the iterator to its initial state (one-before-first) +// Call Next() to fetch the first element if any. +func (iterator *Iterator) Begin() { + iterator.index = -1 + iterator.element = nil +} + +// First moves the iterator to the first element and returns true if there was a first element in the container. +// If First() returns true, then first element's index and value can be retrieved by Index() and Value(). +// Modifies the state of the iterator. +func (iterator *Iterator) First() bool { + iterator.Begin() + return iterator.Next() +} + // Each calls the given function once for each element, passing that element's index and value. func (list *List) Each(f func(index int, value interface{})) { iterator := list.Iterator() diff --git a/lists/singlylinkedlist/singlylinkedlist_test.go b/lists/singlylinkedlist/singlylinkedlist_test.go index 53c2ad8..03f9b2d 100644 --- a/lists/singlylinkedlist/singlylinkedlist_test.go +++ b/lists/singlylinkedlist/singlylinkedlist_test.go @@ -338,6 +338,35 @@ func TestListIteratorNext(t *testing.T) { } } +func TestListIteratorBegin(t *testing.T) { + list := New() + it := list.Iterator() + it.Begin() + list.Add("a", "b", "c") + for it.Next() { + } + it.Begin() + it.Next() + if index, value := it.Index(), it.Value(); index != 0 || value != "a" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "a") + } +} + +func TestListIteratorFirst(t *testing.T) { + list := New() + it := list.Iterator() + if actualValue, expectedValue := it.First(), false; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + list.Add("a", "b", "c") + if actualValue, expectedValue := it.First(), true; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if index, value := it.Index(), it.Value(); index != 0 || value != "a" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "a") + } +} + func BenchmarkList(b *testing.B) { for i := 0; i < b.N; i++ { list := New() diff --git a/maps/treemap/treemap.go b/maps/treemap/treemap.go index f1640bf..995d25b 100644 --- a/maps/treemap/treemap.go +++ b/maps/treemap/treemap.go @@ -140,13 +140,14 @@ func (m *Map) Iterator() Iterator { // Next moves the iterator to the next element and returns true if there was a next element in the container. // If Next() returns true, then next element's key and value can be retrieved by Key() and Value(). +// If Next() was called for the first time, then it will point the iterator to the first element if it exists. // Modifies the state of the iterator. func (iterator *Iterator) Next() bool { return iterator.iterator.Next() } // Prev moves the iterator to the previous element and returns true if there was a previous element in the container. -// If Prev() returns true, then previous element's index and value can be retrieved by Key() and Value(). +// If Prev() returns true, then previous element's key and value can be retrieved by Key() and Value(). // Modifies the state of the iterator. func (iterator *Iterator) Prev() bool { return iterator.iterator.Prev() @@ -164,6 +165,32 @@ func (iterator *Iterator) Key() interface{} { return iterator.iterator.Key() } +// Begin resets the iterator to its initial state (one-before-first) +// Call Next() to fetch the first element if any. +func (iterator *Iterator) Begin() { + iterator.iterator.Begin() +} + +// End moves the iterator past the last element (one-past-the-end). +// Call Prev() to fetch the last element if any. +func (iterator *Iterator) End() { + iterator.iterator.End() +} + +// First moves the iterator to the first element and returns true if there was a first element in the container. +// If First() returns true, then first element's key and value can be retrieved by Key() and Value(). +// Modifies the state of the iterator +func (iterator *Iterator) First() bool { + return iterator.iterator.First() +} + +// Last moves the iterator to the last element and returns true if there was a last element in the container. +// If Last() returns true, then last element's key and value can be retrieved by Key() and Value(). +// Modifies the state of the iterator. +func (iterator *Iterator) Last() bool { + return iterator.iterator.Last() +} + // Each calls the given function once for each element, passing that element's key and value. func (m *Map) Each(f func(key interface{}, value interface{})) { iterator := m.Iterator() diff --git a/maps/treemap/treemap_test.go b/maps/treemap/treemap_test.go index ac4d778..b896f36 100644 --- a/maps/treemap/treemap_test.go +++ b/maps/treemap/treemap_test.go @@ -377,7 +377,6 @@ func TestMapIteratorPrev(t *testing.T) { } countDown := m.Size() for it.Prev() { - countDown-- key := it.Key() value := it.Value() switch key { @@ -399,13 +398,70 @@ func TestMapIteratorPrev(t *testing.T) { if actualValue, expectedValue := value, countDown; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } + countDown-- } - // one less that in Next(), thus "1" - if actualValue, expectedValue := countDown, 1; actualValue != expectedValue { + if actualValue, expectedValue := countDown, 0; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } } +func TestMapIteratorBegin(t *testing.T) { + m := NewWithIntComparator() + it := m.Iterator() + it.Begin() + m.Put(3, "c") + m.Put(1, "a") + m.Put(2, "b") + for it.Next() { + } + it.Begin() + it.Next() + if key, value := it.Key(), it.Value(); key != 1 || value != "a" { + t.Errorf("Got %v,%v expected %v,%v", key, value, 1, "a") + } +} + +func TestMapTreeIteratorEnd(t *testing.T) { + m := NewWithIntComparator() + it := m.Iterator() + m.Put(3, "c") + m.Put(1, "a") + m.Put(2, "b") + it.End() + it.Prev() + if key, value := it.Key(), it.Value(); key != 3 || value != "c" { + t.Errorf("Got %v,%v expected %v,%v", key, value, 3, "c") + } +} + +func TestMapIteratorFirst(t *testing.T) { + m := NewWithIntComparator() + m.Put(3, "c") + m.Put(1, "a") + m.Put(2, "b") + it := m.Iterator() + if actualValue, expectedValue := it.First(), true; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if key, value := it.Key(), it.Value(); key != 1 || value != "a" { + t.Errorf("Got %v,%v expected %v,%v", key, value, 1, "a") + } +} + +func TestMapIteratorLast(t *testing.T) { + m := NewWithIntComparator() + m.Put(3, "c") + m.Put(1, "a") + m.Put(2, "b") + it := m.Iterator() + if actualValue, expectedValue := it.Last(), true; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if key, value := it.Key(), it.Value(); key != 3 || value != "c" { + t.Errorf("Got %v,%v expected %v,%v", key, value, 3, "c") + } +} + func BenchmarkMap(b *testing.B) { for i := 0; i < b.N; i++ { m := NewWithIntComparator() diff --git a/sets/treeset/treeset.go b/sets/treeset/treeset.go index 3a0de08..6651bae 100644 --- a/sets/treeset/treeset.go +++ b/sets/treeset/treeset.go @@ -120,6 +120,7 @@ func (set *Set) Iterator() Iterator { // Next moves the iterator to the next element and returns true if there was a next element in the container. // If Next() returns true, then next element's index and value can be retrieved by Index() and Value(). +// If Next() was called for the first time, then it will point the iterator to the first element if it exists. // Modifies the state of the iterator. func (iterator *Iterator) Next() bool { if iterator.index < iterator.tree.Size() { @@ -150,6 +151,36 @@ func (iterator *Iterator) Index() int { return iterator.index } +// Begin resets the iterator to its initial state (one-before-first) +// Call Next() to fetch the first element if any. +func (iterator *Iterator) Begin() { + iterator.index = -1 + iterator.iterator.Begin() +} + +// End moves the iterator past the last element (one-past-the-end). +// Call Prev() to fetch the last element if any. +func (iterator *Iterator) End() { + iterator.index = iterator.tree.Size() + iterator.iterator.End() +} + +// First moves the iterator to the first element and returns true if there was a first element in the container. +// If First() returns true, then first element's index and value can be retrieved by Index() and Value(). +// Modifies the state of the iterator. +func (iterator *Iterator) First() bool { + iterator.Begin() + return iterator.Next() +} + +// Last moves the iterator to the last element and returns true if there was a last element in the container. +// If Last() returns true, then last element's index and value can be retrieved by Index() and Value(). +// Modifies the state of the iterator. +func (iterator *Iterator) Last() bool { + iterator.End() + return iterator.iterator.Last() +} + // Each calls the given function once for each element, passing that element's index and value. func (set *Set) Each(f func(index int, value interface{})) { iterator := set.Iterator() diff --git a/sets/treeset/treeset_test.go b/sets/treeset/treeset_test.go index ccdb16c..c0d21af 100644 --- a/sets/treeset/treeset_test.go +++ b/sets/treeset/treeset_test.go @@ -278,6 +278,69 @@ func TestSetIteratorPrev(t *testing.T) { } } +func TestSetIteratorBegin(t *testing.T) { + m := NewWithStringComparator() + it := m.Iterator() + it.Begin() + m.Add("a", "b", "c") + for it.Next() { + } + it.Begin() + it.Next() + if index, value := it.Index(), it.Value(); index != 0 || value != "a" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "a") + } +} + +func TestSetIteratorEnd(t *testing.T) { + set := NewWithStringComparator() + it := set.Iterator() + + if index := it.Index(); index != -1 { + t.Errorf("Got %v expected %v", index, -1) + } + + it.End() + if index := it.Index(); index != 0 { + t.Errorf("Got %v expected %v", index, 0) + } + + set.Add("a", "b", "c") + it.End() + if index := it.Index(); index != set.Size() { + t.Errorf("Got %v expected %v", index, set.Size()) + } + + it.Prev() + if index, value := it.Index(), it.Value(); index != set.Size()-1 || value != "c" { + t.Errorf("Got %v,%v expected %v,%v", index, value, set.Size()-1, "c") + } +} + +func TestSetIteratorFirst(t *testing.T) { + set := NewWithStringComparator() + set.Add("a", "b", "c") + it := set.Iterator() + if actualValue, expectedValue := it.First(), true; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if index, value := it.Index(), it.Value(); index != 0 || value != "a" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "a") + } +} + +func TestSetIteratorLast(t *testing.T) { + set := NewWithStringComparator() + set.Add("a", "b", "c") + it := set.Iterator() + if actualValue, expectedValue := it.Last(), true; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if index, value := it.Index(), it.Value(); index != 3 || value != "c" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 3, "c") + } +} + func BenchmarkSet(b *testing.B) { for i := 0; i < b.N; i++ { set := NewWithIntComparator() diff --git a/stacks/arraystack/arraystack.go b/stacks/arraystack/arraystack.go index ece76a9..ee7cc82 100644 --- a/stacks/arraystack/arraystack.go +++ b/stacks/arraystack/arraystack.go @@ -111,6 +111,7 @@ func (stack *Stack) Iterator() Iterator { // Next moves the iterator to the next element and returns true if there was a next element in the container. // If Next() returns true, then next element's index and value can be retrieved by Index() and Value(). +// If Next() was called for the first time, then it will point the iterator to the first element if it exists. // Modifies the state of the iterator. func (iterator *Iterator) Next() bool { if iterator.index < iterator.stack.Size() { @@ -142,6 +143,34 @@ func (iterator *Iterator) Index() int { return iterator.index } +// Begin resets the iterator to its initial state (one-before-first) +// Call Next() to fetch the first element if any. +func (iterator *Iterator) Begin() { + iterator.index = -1 +} + +// End moves the iterator past the last element (one-past-the-end). +// Call Prev() to fetch the last element if any. +func (iterator *Iterator) End() { + iterator.index = iterator.stack.Size() +} + +// First moves the iterator to the first element and returns true if there was a first element in the container. +// If First() returns true, then first element's index and value can be retrieved by Index() and Value(). +// Modifies the state of the iterator. +func (iterator *Iterator) First() bool { + iterator.Begin() + return iterator.Next() +} + +// Last moves the iterator to the last element and returns true if there was a last element in the container. +// If Last() returns true, then last element's index and value can be retrieved by Index() and Value(). +// Modifies the state of the iterator. +func (iterator *Iterator) Last() bool { + iterator.End() + return iterator.Prev() +} + // String returns a string representation of container func (stack *Stack) String() string { str := "ArrayStack\n" diff --git a/stacks/arraystack/arraystack_test.go b/stacks/arraystack/arraystack_test.go index fad4ac0..ed27db0 100644 --- a/stacks/arraystack/arraystack_test.go +++ b/stacks/arraystack/arraystack_test.go @@ -176,6 +176,83 @@ func TestStackIteratorPrev(t *testing.T) { } } +func TestStackIteratorBegin(t *testing.T) { + stack := New() + it := stack.Iterator() + it.Begin() + stack.Push("a") + stack.Push("b") + stack.Push("c") + for it.Next() { + } + it.Begin() + it.Next() + if index, value := it.Index(), it.Value(); index != 0 || value != "c" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "c") + } +} + +func TestStackIteratorEnd(t *testing.T) { + stack := New() + it := stack.Iterator() + + if index := it.Index(); index != -1 { + t.Errorf("Got %v expected %v", index, -1) + } + + it.End() + if index := it.Index(); index != 0 { + t.Errorf("Got %v expected %v", index, 0) + } + + stack.Push("a") + stack.Push("b") + stack.Push("c") + it.End() + if index := it.Index(); index != stack.Size() { + t.Errorf("Got %v expected %v", index, stack.Size()) + } + + it.Prev() + if index, value := it.Index(), it.Value(); index != stack.Size()-1 || value != "a" { + t.Errorf("Got %v,%v expected %v,%v", index, value, stack.Size()-1, "a") + } +} + +func TestStackIteratorFirst(t *testing.T) { + stack := New() + it := stack.Iterator() + if actualValue, expectedValue := it.First(), false; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + stack.Push("a") + stack.Push("b") + stack.Push("c") + if actualValue, expectedValue := it.First(), true; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if index, value := it.Index(), it.Value(); index != 0 || value != "c" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "c") + } +} + +func TestStackIteratorLast(t *testing.T) { + stack := New() + it := stack.Iterator() + if actualValue, expectedValue := it.Last(), false; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + stack.Push("a") + stack.Push("b") + stack.Push("c") + if actualValue, expectedValue := it.Last(), true; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if index, value := it.Index(), it.Value(); index != 2 || value != "a" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "a") + } +} + func BenchmarkStack(b *testing.B) { for i := 0; i < b.N; i++ { stack := New() diff --git a/stacks/linkedliststack/linkedliststack.go b/stacks/linkedliststack/linkedliststack.go index 75f1948..0778f6d 100644 --- a/stacks/linkedliststack/linkedliststack.go +++ b/stacks/linkedliststack/linkedliststack.go @@ -106,6 +106,7 @@ func (stack *Stack) Iterator() Iterator { // Next moves the iterator to the next element and returns true if there was a next element in the container. // If Next() returns true, then next element's index and value can be retrieved by Index() and Value(). +// If Next() was called for the first time, then it will point the iterator to the first element if it exists. // Modifies the state of the iterator. func (iterator *Iterator) Next() bool { if iterator.index < iterator.stack.Size() { @@ -127,6 +128,20 @@ func (iterator *Iterator) Index() int { return iterator.index } +// Begin resets the iterator to its initial state (one-before-first) +// Call Next() to fetch the first element if any. +func (iterator *Iterator) Begin() { + iterator.index = -1 +} + +// First moves the iterator to the first element and returns true if there was a first element in the container. +// If First() returns true, then first element's index and value can be retrieved by Index() and Value(). +// Modifies the state of the iterator. +func (iterator *Iterator) First() bool { + iterator.Begin() + return iterator.Next() +} + // String returns a string representation of container func (stack *Stack) String() string { str := "LinkedListStack\n" diff --git a/stacks/linkedliststack/linkedliststack_test.go b/stacks/linkedliststack/linkedliststack_test.go index 4fb0002..ec218cb 100644 --- a/stacks/linkedliststack/linkedliststack_test.go +++ b/stacks/linkedliststack/linkedliststack_test.go @@ -136,6 +136,39 @@ func TestStackIterator(t *testing.T) { } } +func TestStackIteratorBegin(t *testing.T) { + stack := New() + it := stack.Iterator() + it.Begin() + stack.Push("a") + stack.Push("b") + stack.Push("c") + for it.Next() { + } + it.Begin() + it.Next() + if index, value := it.Index(), it.Value(); index != 0 || value != "c" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "c") + } +} + +func TestStackIteratorFirst(t *testing.T) { + stack := New() + it := stack.Iterator() + if actualValue, expectedValue := it.First(), false; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + stack.Push("a") + stack.Push("b") + stack.Push("c") + if actualValue, expectedValue := it.First(), true; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if index, value := it.Index(), it.Value(); index != 0 || value != "c" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "c") + } +} + func BenchmarkStack(b *testing.B) { for i := 0; i < b.N; i++ { stack := New() diff --git a/trees/binaryheap/binaryheap.go b/trees/binaryheap/binaryheap.go index 0e5942f..4845c31 100644 --- a/trees/binaryheap/binaryheap.go +++ b/trees/binaryheap/binaryheap.go @@ -127,6 +127,7 @@ func (heap *Heap) Iterator() Iterator { // Next moves the iterator to the next element and returns true if there was a next element in the container. // If Next() returns true, then next element's index and value can be retrieved by Index() and Value(). +// If Next() was called for the first time, then it will point the iterator to the first element if it exists. // Modifies the state of the iterator. func (iterator *Iterator) Next() bool { if iterator.index < iterator.heap.Size() { @@ -158,6 +159,34 @@ func (iterator *Iterator) Index() int { return iterator.index } +// Begin resets the iterator to its initial state (one-before-first) +// Call Next() to fetch the first element if any. +func (iterator *Iterator) Begin() { + iterator.index = -1 +} + +// End moves the iterator past the last element (one-past-the-end). +// Call Prev() to fetch the last element if any. +func (iterator *Iterator) End() { + iterator.index = iterator.heap.Size() +} + +// First moves the iterator to the first element and returns true if there was a first element in the container. +// If First() returns true, then first element's index and value can be retrieved by Index() and Value(). +// Modifies the state of the iterator. +func (iterator *Iterator) First() bool { + iterator.Begin() + return iterator.Next() +} + +// Last moves the iterator to the last element and returns true if there was a last element in the container. +// If Last() returns true, then last element's index and value can be retrieved by Index() and Value(). +// Modifies the state of the iterator. +func (iterator *Iterator) Last() bool { + iterator.End() + return iterator.Prev() +} + // String returns a string representation of container func (heap *Heap) String() string { str := "BinaryHeap\n" diff --git a/trees/binaryheap/binaryheap_test.go b/trees/binaryheap/binaryheap_test.go index d72375a..916f9e5 100644 --- a/trees/binaryheap/binaryheap_test.go +++ b/trees/binaryheap/binaryheap_test.go @@ -191,6 +191,83 @@ func TestBinaryHeapIteratorPrev(t *testing.T) { } } +func TestBinaryHeapIteratorBegin(t *testing.T) { + heap := NewWithIntComparator() + it := heap.Iterator() + it.Begin() + heap.Push(2) + heap.Push(3) + heap.Push(1) + for it.Next() { + } + it.Begin() + it.Next() + if index, value := it.Index(), it.Value(); index != 0 || value != 1 { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, 1) + } +} + +func TestListIteratorEnd(t *testing.T) { + heap := NewWithIntComparator() + it := heap.Iterator() + + if index := it.Index(); index != -1 { + t.Errorf("Got %v expected %v", index, -1) + } + + it.End() + if index := it.Index(); index != 0 { + t.Errorf("Got %v expected %v", index, 0) + } + + heap.Push(3) // [3] + heap.Push(2) // [2,3] + heap.Push(1) // [1,3,2](2 swapped with 1, hence last) + it.End() + if index := it.Index(); index != heap.Size() { + t.Errorf("Got %v expected %v", index, heap.Size()) + } + + it.Prev() + if index, value := it.Index(), it.Value(); index != heap.Size()-1 || value != 2 { + t.Errorf("Got %v,%v expected %v,%v", index, value, heap.Size()-1, 2) + } +} + +func TestStackIteratorFirst(t *testing.T) { + heap := NewWithIntComparator() + it := heap.Iterator() + if actualValue, expectedValue := it.First(), false; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + heap.Push(3) // [3] + heap.Push(2) // [2,3] + heap.Push(1) // [1,3,2](2 swapped with 1, hence last) + if actualValue, expectedValue := it.First(), true; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if index, value := it.Index(), it.Value(); index != 0 || value != 1 { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, 1) + } +} + +func TestBinaryHeapIteratorLast(t *testing.T) { + tree := NewWithIntComparator() + it := tree.Iterator() + if actualValue, expectedValue := it.Last(), false; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + tree.Push(2) + tree.Push(3) + tree.Push(1) // [1,3,2](2 swapped with 1, hence last) + if actualValue, expectedValue := it.Last(), true; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if index, value := it.Index(), it.Value(); index != 2 || value != 2 { + t.Errorf("Got %v,%v expected %v,%v", index, value, 2, 2) + } +} + func BenchmarkBinaryHeap(b *testing.B) { for i := 0; i < b.N; i++ { heap := NewWithIntComparator() diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index cf68bab..7d6f083 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -280,68 +280,105 @@ func (tree *Tree) Clear() { // Iterator holding the iterator's state type Iterator struct { - tree *Tree - node *Node + tree *Tree + node *Node + position position } +type position byte + +const ( + begin, between, end position = 0, 1, 2 +) + // Iterator returns a stateful iterator whose elements are key/value pairs. func (tree *Tree) Iterator() Iterator { - return Iterator{tree: tree, node: nil} + return Iterator{tree: tree, node: nil, position: begin} } // Next moves the iterator to the next element and returns true if there was a next element in the container. // If Next() returns true, then next element's key and value can be retrieved by Key() and Value(). +// If Next() was called for the first time, then it will point the iterator to the first element if it exists. // Modifies the state of the iterator. func (iterator *Iterator) Next() bool { - if iterator.node == nil { - iterator.node = iterator.tree.Left() - return iterator.node != nil + if iterator.position == end { + goto end + } + if iterator.position == begin { + left := iterator.tree.Left() + if left == nil { + goto end + } + iterator.node = left + goto between } if iterator.node.Right != nil { iterator.node = iterator.node.Right for iterator.node.Left != nil { iterator.node = iterator.node.Left } - return true + goto between } if iterator.node.Parent != nil { node := iterator.node for iterator.node.Parent != nil { iterator.node = iterator.node.Parent if iterator.tree.Comparator(node.Key, iterator.node.Key) <= 0 { - return true + goto between } } - iterator.node = node // fix: if parent didn't satisfy the comparator criteria } + +end: + iterator.node = nil + iterator.position = end return false + +between: + iterator.position = between + return true } // Prev moves the iterator to the previous element and returns true if there was a previous element in the container. -// If Prev() returns true, then previous element's index and value can be retrieved by Key() and Value(). +// If Prev() returns true, then previous element's key and value can be retrieved by Key() and Value(). // Modifies the state of the iterator. func (iterator *Iterator) Prev() bool { - if iterator.node == nil { - return false + if iterator.position == begin { + goto begin + } + if iterator.position == end { + right := iterator.tree.Right() + if right == nil { + goto begin + } + iterator.node = right + goto between } if iterator.node.Left != nil { iterator.node = iterator.node.Left for iterator.node.Right != nil { iterator.node = iterator.node.Right } - return true + goto between } if iterator.node.Parent != nil { node := iterator.node for iterator.node.Parent != nil { iterator.node = iterator.node.Parent if iterator.tree.Comparator(node.Key, iterator.node.Key) >= 0 { - return true + goto between } } - iterator.node = node // fix: if parent didn't satisfy the comparator criteria } + +begin: + iterator.node = nil + iterator.position = begin return false + +between: + iterator.position = between + return true } // Value returns the current element's value. @@ -356,6 +393,36 @@ func (iterator *Iterator) Key() interface{} { return iterator.node.Key } +// Begin resets the iterator to its initial state (one-before-first) +// Call Next() to fetch the first element if any. +func (iterator *Iterator) Begin() { + iterator.node = nil + iterator.position = begin +} + +// End moves the iterator past the last element (one-past-the-end). +// Call Prev() to fetch the last element if any. +func (iterator *Iterator) End() { + iterator.node = nil + iterator.position = end +} + +// First moves the iterator to the first element and returns true if there was a first element in the container. +// If First() returns true, then first element's key and value can be retrieved by Key() and Value(). +// Modifies the state of the iterator +func (iterator *Iterator) First() bool { + iterator.Begin() + return iterator.Next() +} + +// Last moves the iterator to the last element and returns true if there was a last element in the container. +// If Last() returns true, then last element's key and value can be retrieved by Key() and Value(). +// Modifies the state of the iterator. +func (iterator *Iterator) Last() bool { + iterator.End() + return iterator.Prev() +} + // String returns a string representation of container func (tree *Tree) String() string { str := "RedBlackTree\n" diff --git a/trees/redblacktree/redblacktree_test.go b/trees/redblacktree/redblacktree_test.go index 3f5987a..3cc5487 100644 --- a/trees/redblacktree/redblacktree_test.go +++ b/trees/redblacktree/redblacktree_test.go @@ -282,7 +282,6 @@ func TestRedBlackTreeIterator1Prev(t *testing.T) { } countDown := tree.size for it.Prev() { - countDown-- key := it.Key() switch key { case countDown: @@ -294,9 +293,9 @@ func TestRedBlackTreeIterator1Prev(t *testing.T) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } } + countDown-- } - // one less that in Next(), thus "1" - if actualValue, expectedValue := countDown, 1; actualValue != expectedValue { + if actualValue, expectedValue := countDown, 0; actualValue != expectedValue { t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) } } @@ -337,7 +336,6 @@ func TestRedBlackTreeIterator2Prev(t *testing.T) { } countDown := tree.size for it.Prev() { - countDown-- key := it.Key() switch key { case countDown: @@ -349,9 +347,9 @@ func TestRedBlackTreeIterator2Prev(t *testing.T) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } } + countDown-- } - // one less that in Next(), thus "1" - if actualValue, expectedValue := countDown, 1; actualValue != expectedValue { + if actualValue, expectedValue := countDown, 0; actualValue != expectedValue { t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) } } @@ -388,7 +386,6 @@ func TestRedBlackTreeIterator3Prev(t *testing.T) { } countDown := tree.size for it.Prev() { - countDown-- key := it.Key() switch key { case countDown: @@ -400,9 +397,9 @@ func TestRedBlackTreeIterator3Prev(t *testing.T) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } } + countDown-- } - // one less that in Next(), thus "1" - if actualValue, expectedValue := countDown, 1; actualValue != expectedValue { + if actualValue, expectedValue := countDown, 0; actualValue != expectedValue { t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) } } @@ -450,7 +447,7 @@ func TestRedBlackTreeIterator4Next(t *testing.T) { } } -func TestRedBlackTreeIterator4(t *testing.T) { +func TestRedBlackTreeIterator4Prev(t *testing.T) { tree := NewWithIntComparator() tree.Put(13, 5) tree.Put(8, 3) @@ -477,7 +474,6 @@ func TestRedBlackTreeIterator4(t *testing.T) { for it.Next() { } for it.Prev() { - count-- value := it.Value() switch value { case count: @@ -489,13 +485,100 @@ func TestRedBlackTreeIterator4(t *testing.T) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } } + count-- } - // one less that in Next(), thus "1" - if actualValue, expectedValue := count, 1; actualValue != expectedValue { + if actualValue, expectedValue := count, 0; actualValue != expectedValue { t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) } } +func TestRedBlackTreeIteratorBegin(t *testing.T) { + tree := NewWithIntComparator() + tree.Put(3, "c") + tree.Put(1, "a") + tree.Put(2, "b") + it := tree.Iterator() + + if it.node != nil { + t.Errorf("Got %v expected %v", it.node, nil) + } + + it.Begin() + + if it.node != nil { + t.Errorf("Got %v expected %v", it.node, nil) + } + + for it.Next() { + } + + it.Begin() + + if it.node != nil { + t.Errorf("Got %v expected %v", it.node, nil) + } + + it.Next() + if key, value := it.Key(), it.Value(); key != 1 || value != "a" { + t.Errorf("Got %v,%v expected %v,%v", key, value, 1, "a") + } +} + +func TestRedBlackTreeIteratorEnd(t *testing.T) { + tree := NewWithIntComparator() + it := tree.Iterator() + + if it.node != nil { + t.Errorf("Got %v expected %v", it.node, nil) + } + + it.End() + if it.node != nil { + t.Errorf("Got %v expected %v", it.node, nil) + } + + tree.Put(3, "c") + tree.Put(1, "a") + tree.Put(2, "b") + it.End() + if it.node != nil { + t.Errorf("Got %v expected %v", it.node, nil) + } + + it.Prev() + if key, value := it.Key(), it.Value(); key != 3 || value != "c" { + t.Errorf("Got %v,%v expected %v,%v", key, value, 3, "c") + } +} + +func TestRedBlackTreeIteratorFirst(t *testing.T) { + tree := NewWithIntComparator() + tree.Put(3, "c") + tree.Put(1, "a") + tree.Put(2, "b") + it := tree.Iterator() + if actualValue, expectedValue := it.First(), true; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if key, value := it.Key(), it.Value(); key != 1 || value != "a" { + t.Errorf("Got %v,%v expected %v,%v", key, value, 1, "a") + } +} + +func TestRedBlackTreeIteratorLast(t *testing.T) { + tree := NewWithIntComparator() + tree.Put(3, "c") + tree.Put(1, "a") + tree.Put(2, "b") + it := tree.Iterator() + if actualValue, expectedValue := it.Last(), true; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if key, value := it.Key(), it.Value(); key != 3 || value != "c" { + t.Errorf("Got %v,%v expected %v,%v", key, value, 3, "c") + } +} + func BenchmarkRedBlackTree(b *testing.B) { for i := 0; i < b.N; i++ { tree := NewWithIntComparator()