- iterator implementation

- tests for arraylist enumerable operations
pull/12/head
Emir Pasic 8 years ago
parent 6fefe7cc24
commit 549ece1100

@ -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{}
}

@ -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)
}
}

@ -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()

Loading…
Cancel
Save