From c5826ac043e612e0f3ee2aea3363004468f38ce9 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sun, 8 Mar 2015 03:13:26 +0100 Subject: [PATCH] sorting on containers, lists and as a utils method (test+documentation) --- README.md | 47 ++++++++++++++++++- containers/containers.go | 14 ++++++ containers/containers_test.go | 77 +++++++++++++++++++++++++++++++ lists/arraylist/arraylist.go | 15 ++++-- lists/arraylist/arraylist_test.go | 15 +++++- lists/lists.go | 6 ++- utils/sort.go | 2 +- 7 files changed, 166 insertions(+), 10 deletions(-) create mode 100644 containers/containers_test.go diff --git a/README.md b/README.md index deda76b..3a8b699 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ Implementation of various data structures in Go. - [RedBlackTree](#redblacktree) - [Functions](#functions) - [Comparator](#comparator) + - [Sort](#sort) ###Containers @@ -38,6 +39,15 @@ type Interface interface { ``` +Container specific operations: + +```go +// Returns sorted container's elements using with respect to the passed comparator. +// Does not effect the ordering of elements within the container. +// Uses timsort. +func GetSortedValues(container Interface, comparator utils.Comparator) []interface{} { +``` + ####Sets A set is a data structure that can store elements and no repeated values. It is a computer implementation of the mathematical concept of a finite set. Unlike most other collection types, rather than retrieving a specific element from a set, one typically tests an element for membership in a set. This structed is often used to ensure that no duplicates are present in a collection. @@ -127,6 +137,7 @@ type Interface interface { Remove(index int) Add(elements ...interface{}) Contains(elements ...interface{}) bool + Sort(comparator utils.Comparator) containers.Interface // Empty() bool @@ -144,9 +155,18 @@ Direct access method _Get(index)_ is guaranteed a constant time performance. Rem ```go +package main + +import ( + "github.com/emirpasic/gods/lists/arraylist" + "github.com/emirpasic/gods/utils" +) + +func main() { list := arraylist.New() list.Add("a") // ["a"] - list.Add("b", "c") // ["a","b","c"] + list.Add("c", "b") // ["a","c","b"] + list.Sort(utils.StringComparator) // ["a","b","c"] _, _ = list.Get(0) // "a",true _, _ = list.Get(100) // nil,false _ = list.Contains("a", "b", "c") // true @@ -500,6 +520,29 @@ func main() { } ``` +#### Sort + +Sort uses timsort for best performance on real-world data. Lists have an in-place _Sort()_ method. All containers can return their sorted elements via _GetSortedValues()_ call. + +Internally they use the _utils.Sort()_ method: + +```go +package main + +import ( + "github.com/emirpasic/gods/utils" +) + +func main() { + strings := []interface{}{} // [] + strings = append(strings, "d") // ["d"] + strings = append(strings, "a") // ["d","a"] + strings = append(strings, "b") // ["d","a",b" + strings = append(strings, "c") // ["d","a",b","c"] + utils.Sort(strings, utils.StringComparator) // ["a","b","c","d"] +} + +``` ## Motivations @@ -509,7 +552,7 @@ Collections and data structures found in other languages: Java Collections, C++ **Fast algorithms**: - - Based on decades of knowledge and experiences of other libraries mentioned below. + - Based on decades of knowledge and experiences of other libraries mentioned above. **Memory efficient algorithms**: diff --git a/containers/containers.go b/containers/containers.go index fc348d2..96d3e07 100644 --- a/containers/containers.go +++ b/containers/containers.go @@ -28,9 +28,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package containers +import "github.com/emirpasic/gods/utils" + type Interface interface { Empty() bool Size() int Clear() Values() []interface{} } + +// Returns sorted container's elements using with respect to the passed comparator. +// Does not effect the ordering of elements within the container. +// Uses timsort. +func GetSortedValues(container Interface, comparator utils.Comparator) []interface{} { + values := container.Values() + if len(values) < 2 { + return values + } + utils.Sort(values, comparator) + return values +} diff --git a/containers/containers_test.go b/containers/containers_test.go new file mode 100644 index 0000000..bef88f4 --- /dev/null +++ b/containers/containers_test.go @@ -0,0 +1,77 @@ +/* +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. +*/ + +// All data structures must implement the container structure + +package containers + +import ( + "github.com/emirpasic/gods/utils" + "testing" +) + +// For testing purposes +type Container struct { + values []interface{} +} + +func (container Container) Empty() bool { + return len(container.values) == 0 +} + +func (container Container) Size() int { + return len(container.values) +} + +func (container Container) Clear() { + container.values = []interface{}{} +} + +func (container Container) Values() []interface{} { + return container.values +} + +func TestGetSortedValuesInts(t *testing.T) { + container := Container{} + container.values = []interface{}{5, 1, 3, 2, 4} + values := GetSortedValues(container, utils.IntComparator) + for i := 1; i < container.Size(); i++ { + if values[i-1].(int) > values[i].(int) { + t.Errorf("Not sorted!") + } + } +} + +func TestGetSortedValuesStrings(t *testing.T) { + container := Container{} + container.values = []interface{}{"g", "a", "d", "e", "f", "c", "b"} + values := GetSortedValues(container, utils.StringComparator) + for i := 1; i < container.Size(); i++ { + if values[i-1].(string) > values[i].(string) { + t.Errorf("Not sorted!") + } + } +} diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index 3e3f13f..3480d5c 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -33,6 +33,7 @@ package arraylist import ( "fmt" "github.com/emirpasic/gods/lists" + "github.com/emirpasic/gods/utils" "strings" ) @@ -133,20 +134,24 @@ func (list *List) Clear() { list.elements = []interface{}{} } +// Sorts values (in-place) using timsort. +func (list *List) Sort(comparator utils.Comparator) { + if len(list.elements) < 2 { + return + } + utils.Sort(list.elements[:list.size], comparator) +} + func (list *List) String() string { str := "ArrayList\n" values := []string{} - for _, value := range list.elements { + for _, value := range list.elements[:list.size] { values = append(values, fmt.Sprintf("%v", value)) } str += strings.Join(values, ", ") return str } -/************* - * Internals * - *************/ - // Check that the index is withing bounds of the list func (list *List) withinRange(index int) bool { return index >= 0 && index < list.size && list.size != 0 diff --git a/lists/arraylist/arraylist_test.go b/lists/arraylist/arraylist_test.go index 3f05f28..5b1e30a 100644 --- a/lists/arraylist/arraylist_test.go +++ b/lists/arraylist/arraylist_test.go @@ -27,6 +27,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package arraylist import ( + "github.com/emirpasic/gods/utils" "testing" ) @@ -34,7 +35,19 @@ func TestArrayList(t *testing.T) { list := New() - list.Add("a", "b", "c", "d", "e", "f", "g") + list.Sort(utils.StringComparator) + + list.Add("e", "f", "g", "a", "b", "c", "d") + + list.Sort(utils.StringComparator) + for i := 1; i < list.Size(); i++ { + a, _ := list.Get(i - 1) + b, _ := list.Get(i) + if a.(string) > b.(string) { + t.Errorf("Not sorted! %s > %s", a, b) + } + } + list.Clear() if actualValue := list.Empty(); actualValue != true { diff --git a/lists/lists.go b/lists/lists.go index 32e71f5..2a01c05 100644 --- a/lists/lists.go +++ b/lists/lists.go @@ -18,13 +18,17 @@ with this distribution for more information. package lists -import "github.com/emirpasic/gods/containers" +import ( + "github.com/emirpasic/gods/containers" + "github.com/emirpasic/gods/utils" +) type Interface interface { Get(index int) (interface{}, bool) Remove(index int) Add(elements ...interface{}) Contains(elements ...interface{}) bool + Sort(comparator utils.Comparator) containers.Interface // Empty() bool diff --git a/utils/sort.go b/utils/sort.go index 51397b3..176a62f 100644 --- a/utils/sort.go +++ b/utils/sort.go @@ -30,7 +30,7 @@ package utils import "github.com/emirpasic/gods/utils/timsort" -// Sorts values (in-place) +// Sorts values (in-place) using timsort func Sort(values []interface{}, comparator Comparator) { less := func(a, b interface{}) bool { return comparator(a, b) < 0 } timsort.Sort(values, less)