Skip to content

Instantly share code, notes, and snippets.

@jrop
Created July 8, 2016 20:39
Show Gist options
  • Save jrop/5f9d3aa75161bcbd61865ef6e2f5d558 to your computer and use it in GitHub Desktop.
Save jrop/5f9d3aa75161bcbd61865ef6e2f5d558 to your computer and use it in GitHub Desktop.
Slowdash (Golang)
package main
import (
"fmt"
"reflect"
"sort"
)
// Item is a generic item
// type Item interface{}
// Collection is a generic collection
type Collection struct {
Data interface{}
}
// OrderableCollection is an ordered collection
type OrderableCollection struct {
Collection Collection
Comparator func(a, b reflect.Value) bool
}
// Len is for sorting
func (oc OrderableCollection) Len() int {
return reflect.ValueOf(oc.Collection.Data).Len()
}
// Less is for sorting
func (oc OrderableCollection) Less(i, j int) bool {
cValue := reflect.ValueOf(oc.Collection.Data)
return oc.Comparator(cValue.Index(i), cValue.Index(j))
}
// Swap is for sorting
func (oc OrderableCollection) Swap(i, j int) {
data := reflect.ValueOf(oc.Collection.Data)
x, y := data.Index(i).Interface(), data.Index(j).Interface()
data.Index(j).Set(reflect.ValueOf(x))
data.Index(i).Set(reflect.ValueOf(y))
}
// NewCollection creates a new collection
func NewCollection(data interface{}) Collection {
return Collection{Data: data}
}
// Map maps a collection
func (a Collection) Map(f func(item interface{}) interface{}) Collection {
aValue := reflect.ValueOf(a.Data)
aLen := aValue.Len()
newData := make([]interface{}, aLen)
for i := 0; i < aLen; i++ {
newData[i] = f(aValue.Index(i).Interface())
}
return Collection{Data: newData}
}
// Filter filters a collection
func (a Collection) Filter(f func(item interface{}) bool) Collection {
aValue := reflect.ValueOf(a.Data)
aLen := aValue.Len()
newData := reflect.MakeSlice(reflect.TypeOf(a.Data), 0, aLen)
for i := 0; i < aLen; i++ {
if f(aValue.Index(i).Interface()) {
newData = reflect.Append(newData, aValue.Index(i))
}
}
return Collection{Data: newData.Interface()}
}
// GroupBy groups a collection
func (a Collection) GroupBy(f func(item interface{}) interface{}) map[interface{}][]interface{} {
aValue := reflect.ValueOf(a.Data)
aLen := aValue.Len()
result := make(map[interface{}][]interface{})
for i := 0; i < aLen; i++ {
groupKey := f(aValue.Index(i).Interface())
if result[groupKey] == nil {
result[groupKey] = make([]interface{}, 0)
}
result[groupKey] = append(result[groupKey], aValue.Index(i).Interface())
}
return result
}
// SortBy sort a collection
func (a Collection) SortBy(f func(item interface{}) interface{}) Collection {
aCopy := a.Map(func(item interface{}) interface{} {
return item
})
comparator := func(a, b reflect.Value) bool {
_a := reflect.ValueOf(f(a.Interface()))
_b := reflect.ValueOf(f(b.Interface()))
if _a.Type() != _b.Type() {
panic("Unuequal types")
}
switch _a.Interface().(type) {
case string:
return _a.Interface().(string) < _b.Interface().(string)
case int:
return _a.Interface().(int) < _b.Interface().(int)
default:
panic("Unsupported type for comparison")
}
}
oc := OrderableCollection{Collection: aCopy, Comparator: comparator}
sort.Sort(oc)
return aCopy
}
// Find finds a value
func (a Collection) Find(f func(item interface{}) bool) (interface{}, bool) {
var val interface{}
found := false
aValue := reflect.ValueOf(a.Data)
aLen := aValue.Len()
for i := 0; i < aLen; i++ {
if f(aValue.Index(i).Interface()) {
val = aValue.Index(i).Interface()
found = true
return val, found
}
}
return val, found
}
// MustFind finds a value
func (a Collection) MustFind(f func(item interface{}) bool) interface{} {
val, ok := a.Find(f)
if !ok {
panic("Item not found")
}
return val
}
// Contains returns true if the collection contains an item that matches the predicate
func (a Collection) Contains(f func(item interface{}) bool) bool {
_, ok := a.Find(f)
return ok
}
// UniqueBy trims out duplicates
func (a Collection) UniqueBy(f func(item interface{}) interface{}) Collection {
aValue := reflect.ValueOf(a.Data)
aLen := aValue.Len()
newData := reflect.MakeSlice(aValue.Type(), 0, 0)
for i := 0; i < aLen; i++ {
val := f(aValue.Index(i).Interface())
tmpCollection := Collection{Data: newData.Interface()}
if !tmpCollection.Contains(func(item interface{}) bool {
if reflect.TypeOf(val) != reflect.TypeOf(item) {
panic("Unequal types")
}
switch val.(type) {
case int:
return val.(int) == item.(int)
case string:
return val.(string) == item.(string)
default:
panic("Uncomparable data types")
}
}) {
newData = reflect.Append(newData, aValue.Index(i))
}
}
return Collection{Data: newData.Interface()}
}
func main() {
a := NewCollection([]int{1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
b := a.
// Map(func(i interface{}) interface{} {
// return i.(int) * 3
// }).
// Filter(func(i interface{}) bool {
// return i.(int) > 6
// }).
SortBy(func(i interface{}) interface{} {
return -i.(int)
}).
UniqueBy(func(i interface{}) interface{} {
return i
})
// GroupBy(func(i interface{}) interface{} {
// if i.(int)%2 == 0 {
// return "even"
// }
// return "odd"
// })
fmt.Println(b)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment