From 76f36e4980dc89fe8047b774c26be6bc6a9e4f5b Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 22 Jun 2016 05:29:21 +0200 Subject: [PATCH] - add enumerable and iterator to singly linked list --- lists/singlylinkedlist/singlylinkedlist.go | 92 +++++++++++++ .../singlylinkedlist/singlylinkedlist_test.go | 125 ++++++++++++++++++ 2 files changed, 217 insertions(+) diff --git a/lists/singlylinkedlist/singlylinkedlist.go b/lists/singlylinkedlist/singlylinkedlist.go index 47ab9b2..69177b3 100644 --- a/lists/singlylinkedlist/singlylinkedlist.go +++ b/lists/singlylinkedlist/singlylinkedlist.go @@ -32,6 +32,7 @@ package singlylinkedlist import ( "fmt" + "github.com/emirpasic/gods/containers" "github.com/emirpasic/gods/lists" "github.com/emirpasic/gods/utils" "strings" @@ -39,6 +40,8 @@ import ( func assertInterfaceImplementation() { var _ lists.List = (*List)(nil) + var _ containers.Enumerable = (*List)(nil) + var _ containers.Iterator = (*Iterator)(nil) } type List struct { @@ -267,6 +270,95 @@ func (list *List) Insert(index int, values ...interface{}) { } } +type Iterator struct { + list *List + index int + element *element +} + +func (list *List) Iterator() Iterator { + return Iterator{list: list, index: -1, element: nil} +} + +func (iterator *Iterator) Next() bool { + iterator.index += 1 + if !iterator.list.withinRange(iterator.index) { + iterator.element = nil + return false + } + if iterator.element == nil { + iterator.element = iterator.list.first + } else { + iterator.element = iterator.element.next + } + return true +} + +func (iterator *Iterator) Value() interface{} { + return iterator.element.value +} + +func (iterator *Iterator) Index() interface{} { + return iterator.index +} + +func (list *List) Each(f func(index interface{}, value interface{})) { + iterator := list.Iterator() + for iterator.Next() { + f(iterator.Index(), iterator.Value()) + } +} + +func (list *List) Map(f func(index interface{}, value interface{}) interface{}) containers.Container { + newList := &List{} + iterator := list.Iterator() + for iterator.Next() { + newList.Add(f(iterator.Index(), iterator.Value())) + } + return newList +} + +func (list *List) Select(f func(index interface{}, value interface{}) bool) containers.Container { + newList := &List{} + iterator := list.Iterator() + for iterator.Next() { + if f(iterator.Index(), iterator.Value()) { + newList.Add(iterator.Value()) + } + } + return newList +} + +func (list *List) Any(f func(index interface{}, value interface{}) bool) bool { + iterator := list.Iterator() + for iterator.Next() { + if f(iterator.Index(), iterator.Value()) { + return true + } + } + return false +} + +func (list *List) All(f func(index interface{}, value interface{}) bool) bool { + iterator := list.Iterator() + for iterator.Next() { + if !f(iterator.Index(), iterator.Value()) { + return false + } + } + return true +} + +func (list *List) Find(f func(index interface{}, value interface{}) bool) (index interface{}, value interface{}) { + iterator := list.Iterator() + for iterator.Next() { + if f(iterator.Index(), iterator.Value()) { + return iterator.Index(), iterator.Value() + } + } + return nil, nil +} + func (list *List) String() string { str := "SinglyLinkedList\n" values := []string{} diff --git a/lists/singlylinkedlist/singlylinkedlist_test.go b/lists/singlylinkedlist/singlylinkedlist_test.go index df08466..48508e7 100644 --- a/lists/singlylinkedlist/singlylinkedlist_test.go +++ b/lists/singlylinkedlist/singlylinkedlist_test.go @@ -135,7 +135,132 @@ func TestSinglyLinkedList(t *testing.T) { if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s%s%s%s%s%s%s%s", list.Values()...), "abcdefghijk"; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } +} + +func TestSinglyLinkedListEnumerableAndIterator(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 BenchmarkSinglyLinkedList(b *testing.B) {