Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement NextTo and PrevTo on iterator #189

Merged
merged 1 commit into from
Apr 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 72 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -983,6 +983,22 @@ for it.Begin(); it.Next(); {
}
```

Seeking to a specific element:

```go
// Seek function, i.e. find element starting with "b"
seek := func(index int, value interface{}) bool {
return strings.HasSuffix(value.(string), "b")
}

// Seek to the condition and continue traversal from that point (forward).
// assumes it.Begin() was called.
for found := it.NextTo(seek); found; found = it.Next() {
index, value := it.Index(), it.Value()
...
}
```

#### IteratorWithKey

An [iterator](#iterator) whose elements are referenced by a key.
Expand Down Expand Up @@ -1010,6 +1026,22 @@ for it.Begin(); it.Next(); {
}
```

Seeking to a specific element from the current iterator position:

```go
// Seek function, i.e. find element starting with "b"
seek := func(key interface{}, value interface{}) bool {
return strings.HasSuffix(value.(string), "b")
}

// Seek to the condition and continue traversal from that point (forward).
// assumes it.Begin() was called.
for found := it.NextTo(seek); found; found = it.Next() {
key, value := it.Key(), it.Value()
...
}
```

#### 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.
Expand All @@ -1031,6 +1063,22 @@ if it.Last() {
}
```

Seeking to a specific element:

```go
// Seek function, i.e. find element starting with "b"
seek := func(index int, value interface{}) bool {
return strings.HasSuffix(value.(string), "b")
}

// Seek to the condition and continue traversal from that point (in reverse).
// assumes it.End() was called.
for found := it.PrevTo(seek); found; found = it.Prev() {
index, value := it.Index(), it.Value()
...
}
```

#### ReverseIteratorWithKey

An [iterator](#iterator) whose elements are referenced by a key. Provides all functions as [IteratorWithKey](#iteratorwithkey), but can also be used for reverse iteration.
Expand All @@ -1052,6 +1100,20 @@ if it.Last() {
}
```

```go
// Seek function, i.e. find element starting with "b"
seek := func(key interface{}, value interface{}) bool {
return strings.HasSuffix(value.(string), "b")
}

// Seek to the condition and continue traversal from that point (in reverse).
// assumes it.End() was called.
for found := it.PrevTo(seek); found; found = it.Prev() {
key, value := it.Key(), it.Value()
...
}
```

### Enumerable

Enumerable functions for ordered containers that implement [EnumerableWithIndex](#enumerablewithindex) or [EnumerableWithKey](#enumerablewithkey) interfaces.
Expand Down Expand Up @@ -1489,13 +1551,19 @@ Coding style:

```shell
# Install tooling and set path:
go get github.com/golang/lint/golint
go get github.com/fzipp/gocyclo
go get github.com/kisielk/errcheck
go install gotest.tools/gotestsum@latest
go install golang.org/x/lint/golint@latest
go install github.com/kisielk/errcheck@latest
export PATH=$PATH:$GOPATH/bin

# Fix errors and warnings:
go fmt ./... && gofmt -s -w . && go vet ./... && go get ./... && go test ./... && golint ./... && gocyclo -avg -over 15 . && errcheck ./...
go fmt ./... &&
go test -v ./... &&
golint -set_exit_status ./... &&
! go fmt ./... 2>&1 | read &&
go vet -v ./... &&
gocyclo -avg -over 15 ../gods &&
errcheck ./...
```

### License
Expand Down
24 changes: 24 additions & 0 deletions containers/iterator.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ type IteratorWithIndex interface {
// 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

// NextTo moves the iterator to the next element from current position that satisfies the condition given by the
// passed function, and returns true if there was a next element in the container.
// If NextTo() returns true, then next element's index and value can be retrieved by Index() and Value().
// Modifies the state of the iterator.
NextTo(func(index int, value interface{}) bool) bool
}

// IteratorWithKey is a stateful iterator for ordered containers whose elements are key value pairs.
Expand All @@ -54,6 +60,12 @@ type IteratorWithKey interface {
// 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

// NextTo moves the iterator to the next element from current position that satisfies the condition given by the
// passed function, and returns true if there was a next element in the container.
// If NextTo() returns true, then next element's key and value can be retrieved by Key() and Value().
// Modifies the state of the iterator.
NextTo(func(key interface{}, value interface{}) bool) bool
}

// ReverseIteratorWithIndex is stateful iterator for ordered containers whose values can be fetched by an index.
Expand All @@ -80,6 +92,12 @@ type ReverseIteratorWithIndex interface {
// Modifies the state of the iterator.
Last() bool

// PrevTo moves the iterator to the previous element from current position that satisfies the condition given by the
// passed function, and returns true if there was a next element in the container.
// If PrevTo() returns true, then next element's index and value can be retrieved by Index() and Value().
// Modifies the state of the iterator.
PrevTo(func(index int, value interface{}) bool) bool

IteratorWithIndex
}

Expand All @@ -105,5 +123,11 @@ type ReverseIteratorWithKey interface {
// Modifies the state of the iterator.
Last() bool

// PrevTo moves the iterator to the previous element from current position that satisfies the condition given by the
// passed function, and returns true if there was a next element in the container.
// If PrevTo() returns true, then next element's key and value can be retrieved by Key() and Value().
// Modifies the state of the iterator.
PrevTo(func(key interface{}, value interface{}) bool) bool

IteratorWithKey
}
29 changes: 29 additions & 0 deletions examples/iteratorwithindex/iteratorwithindex.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package main
import (
"fmt"
"github.com/emirpasic/gods/sets/treeset"
"strings"
)

// IteratorWithIndexExample to demonstrate basic usage of IteratorWithIndex
Expand Down Expand Up @@ -48,4 +49,32 @@ func main() {
fmt.Print("\nLast index: ", it.Index()) // Last index: 3
fmt.Print("\nLast value: ", it.Value()) // Last value: c
}

// Seek element starting with "b"
seek := func(index int, value interface{}) bool {
return strings.HasSuffix(value.(string), "b")
}

it.Begin()
for found := it.NextTo(seek); found; found = it.Next() {
fmt.Print("\nNextTo index: ", it.Index())
fmt.Print("\nNextTo value: ", it.Value())
} /*
NextTo index: 1
NextTo value: "b"
NextTo index: 2
NextTo value: "c"
*/

it.End()
for found := it.PrevTo(seek); found; found = it.Prev() {
fmt.Print("\nNextTo index: ", it.Index())
fmt.Print("\nNextTo value: ", it.Value())
} /*
NextTo index: 1
NextTo value: "b"
NextTo index: 0
NextTo value: "a"
*/

}
36 changes: 32 additions & 4 deletions examples/iteratorwithkey/iteratorwithkey.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@ package main
import (
"fmt"
"github.com/emirpasic/gods/maps/treemap"
"strings"
)

// IteratorWithKeyExample to demonstrate basic usage of IteratorWithKey
func main() {
m := treemap.NewWithIntComparator()
m.Put(1, "a")
m.Put(2, "b")
m.Put(3, "a")
m.Put(0, "a")
m.Put(1, "b")
m.Put(2, "c")
it := m.Iterator()

fmt.Print("\nForward iteration\n")
Expand Down Expand Up @@ -47,7 +48,34 @@ func main() {
}

if it.Last() {
fmt.Print("\nLast key: ", it.Key()) // Last key: 3
fmt.Print("\nLast key: ", it.Key()) // Last key: 2
fmt.Print("\nLast value: ", it.Value()) // Last value: c
}

// Seek key-value pair whose value starts with "b"
seek := func(key interface{}, value interface{}) bool {
return strings.HasSuffix(value.(string), "b")
}

it.Begin()
for found := it.NextTo(seek); found; found = it.Next() {
fmt.Print("\nNextTo key: ", it.Key())
fmt.Print("\nNextTo value: ", it.Value())
} /*
NextTo key: 1
NextTo value: "b"
NextTo key: 2
NextTo value: "c"
*/

it.End()
for found := it.PrevTo(seek); found; found = it.Prev() {
fmt.Print("\nNextTo key: ", it.Key())
fmt.Print("\nNextTo value: ", it.Value())
} /*
NextTo key: 1
NextTo value: "b"
NextTo key: 0
NextTo value: "a"
*/
}
101 changes: 101 additions & 0 deletions lists/arraylist/arraylist_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package arraylist
import (
"fmt"
"github.com/emirpasic/gods/utils"
"strings"
"testing"
)

Expand Down Expand Up @@ -500,6 +501,106 @@ func TestListIteratorLast(t *testing.T) {
}
}

func TestListIteratorNextTo(t *testing.T) {
// Sample seek function, i.e. string starting with "b"
seek := func(index int, value interface{}) bool {
return strings.HasSuffix(value.(string), "b")
}

// NextTo (empty)
{
list := New()
it := list.Iterator()
for it.NextTo(seek) {
t.Errorf("Shouldn't iterate on empty list")
}
}

// NextTo (not found)
{
list := New()
list.Add("xx", "yy")
it := list.Iterator()
for it.NextTo(seek) {
t.Errorf("Shouldn't iterate on empty list")
}
}

// NextTo (found)
{
list := New()
list.Add("aa", "bb", "cc")
it := list.Iterator()
it.Begin()
if !it.NextTo(seek) {
t.Errorf("Shouldn't iterate on empty list")
}
if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" {
t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb")
}
if !it.Next() {
t.Errorf("Should go to first element")
}
if index, value := it.Index(), it.Value(); index != 2 || value.(string) != "cc" {
t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "cc")
}
if it.Next() {
t.Errorf("Should not go past last element")
}
}
}

func TestListIteratorPrevTo(t *testing.T) {
// Sample seek function, i.e. string starting with "b"
seek := func(index int, value interface{}) bool {
return strings.HasSuffix(value.(string), "b")
}

// PrevTo (empty)
{
list := New()
it := list.Iterator()
it.End()
for it.PrevTo(seek) {
t.Errorf("Shouldn't iterate on empty list")
}
}

// PrevTo (not found)
{
list := New()
list.Add("xx", "yy")
it := list.Iterator()
it.End()
for it.PrevTo(seek) {
t.Errorf("Shouldn't iterate on empty list")
}
}

// PrevTo (found)
{
list := New()
list.Add("aa", "bb", "cc")
it := list.Iterator()
it.End()
if !it.PrevTo(seek) {
t.Errorf("Shouldn't iterate on empty list")
}
if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" {
t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb")
}
if !it.Prev() {
t.Errorf("Should go to first element")
}
if index, value := it.Index(), it.Value(); index != 0 || value.(string) != "aa" {
t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "aa")
}
if it.Prev() {
t.Errorf("Should not go before first element")
}
}
}

func TestListSerialization(t *testing.T) {
list := New()
list.Add("a", "b", "c")
Expand Down
Loading