Skip to content
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,3 +177,4 @@ problems from
* [Day 163](https://github.com/vaskoz/dailycodingproblem-go/issues/336)
* [Day 164](https://github.com/vaskoz/dailycodingproblem-go/issues/340)
* [Day 165](https://github.com/vaskoz/dailycodingproblem-go/issues/343)
* [Day 166](https://github.com/vaskoz/dailycodingproblem-go/issues/346)
78 changes: 78 additions & 0 deletions day166/problem.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package day166

import (
"errors"
)

var errNoMoreElements = errors.New("no more elements to iterate")

// ErrNoMoreElements is returned when there are no more elements to iterate.
func ErrNoMoreElements() error {
return errNoMoreElements
}

// TwoDimensionalIterator can iterate over a slice of slices of anything.
type TwoDimensionalIterator interface {
Next() (interface{}, error)
HasNext() bool
}

type twoDimensionalIterator struct {
sliceIndex, positionInSlice int
finished bool
data [][]interface{}
}

// NewTwoDimensionalIterator returns a new instance of TwoDimensionalIterator.
func NewTwoDimensionalIterator(data [][]interface{}) TwoDimensionalIterator {
finished := true
var sliceIndex, positionInSlice int
for i := range data {
for j := range data[i] {
finished = false
sliceIndex = i
positionInSlice = j
break
}
if !finished {
break
}
}
return &twoDimensionalIterator{
sliceIndex: sliceIndex, finished: finished, positionInSlice: positionInSlice, data: data,
}
}

func (tdi *twoDimensionalIterator) Next() (interface{}, error) {
if tdi.finished {
return nil, ErrNoMoreElements()
}
sliceIndex := -1
positionIndex := 0
for i := tdi.sliceIndex; i < len(tdi.data); i++ {
positionIndex = 0
if i == tdi.sliceIndex {
positionIndex = tdi.positionInSlice + 1
}
for j := positionIndex; j < len(tdi.data[i]); j++ {
sliceIndex = i
positionIndex = j
break
}
if sliceIndex != -1 {
break
}
}
result := tdi.data[tdi.sliceIndex][tdi.positionInSlice]
if sliceIndex == -1 {
tdi.finished = true
} else {
tdi.sliceIndex = sliceIndex
tdi.positionInSlice = positionIndex
}
return result, nil
}

func (tdi *twoDimensionalIterator) HasNext() bool {
return !tdi.finished
}
49 changes: 49 additions & 0 deletions day166/problem_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package day166

import "testing"

var testcases = []struct {
input [][]interface{}
expected []interface{}
}{
{[][]interface{}{
{1, 2}, {3}, {}, {4, 5, 6},
},
[]interface{}{1, 2, 3, 4, 5, 6},
},
{nil, []interface{}{}},
{[][]interface{}{{}, {}, {}}, []interface{}{}},
}

func TestTwoDimensionalIterator(t *testing.T) {
t.Parallel()
for _, tc := range testcases {
tdi := NewTwoDimensionalIterator(tc.input)
for _, v := range tc.expected {
if !tdi.HasNext() {
t.Error("HasNext should return true")
}
if result, err := tdi.Next(); result != v || err != nil {
t.Errorf("Expected (%v,nil) and got (%v,%v)", v, result, err)
}
}
if tdi.HasNext() {
t.Error("HasNext should return false")
}
if _, err := tdi.Next(); err == nil {
t.Errorf("Expected an error on Next when HasNext is false")
}
}
}

func BenchmarkTwoDimensionalIterator(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, tc := range testcases {
tdi := NewTwoDimensionalIterator(tc.input)
for range tc.expected {
tdi.Next()
tdi.HasNext()
}
}
}
}