├── LICENSE ├── README.md ├── any.go ├── any_test.go ├── each.go ├── each_test.go ├── every.go ├── every_test.go ├── indexof.go ├── indexof_test.go ├── map.go ├── map_test.go ├── none.go ├── none_test.go ├── partition.go ├── partition_test.go ├── src ├── underscore.go.old └── underscore_test.go.old ├── underscore.go └── underscore_test.go /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | __ underscore.go 4 | Copyright (c) 2014 Toby Hede 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Underscore.go 2 | ========================================== 3 | 4 | Move Fast; Optimize Late 5 | ------------------------------------------ 6 | 7 | A useful collection of Go utilities. Designed for programmer happiness. 8 | 9 | TL;DR Sort-of like underscore.js, but for Go 10 | 11 | API Documentation 12 | ------------------------------------------ 13 | [GoDoc is WorkInProgress](https://godoc.org/github.com/tobyhede/go-underscore) 14 | 15 | 16 | :warning: Warning 17 | ------------------------------------------ 18 | This package is in heavy flux at the moment as I work to incorporate feedback from various sources. 19 | 20 | 21 | :squirrel: Todo 22 | ------------------------------------------ 23 | 24 | - [ ] godoc 25 | - [ ] contains 26 | - [ ] indexOf 27 | - [ ] worker pools 28 | - [x] parallel each 29 | - [x] parallel map with worker pool 30 | - [x] refactor to make functions first parameter (eg Each func(func(A), []A)) 31 | - [x] handle maps & slices 32 | - [x] all 33 | - [x] any 34 | - [x] none 35 | 36 | 37 | 38 | ------------------------------------------ 39 | * [Notes on Typed Functions](#typed) 40 | * [Any](#any) 41 | * [Each](#each) 42 | * [Every](#every) 43 | * [Map](#map) 44 | * [None](#none) 45 | 46 | 47 | ### Typed Functions ### 48 | --------------------------------------------------------------------------- 49 | 50 | 51 | ### Any ### 52 | --------------------------------------------------------------------------- 53 | 54 | 55 | ### Each ### 56 | --------------------------------------------------------------------------- 57 | 58 | Each func(func(A int), []A) 59 | Each func(func(A B), []A) 60 | 61 | 62 | Applies the given iterator function to each element of a collection (slice or map). 63 | 64 | If the collection is a Slice, the iterator function arguments are *value, index* 65 | 66 | If the collection is a Map, the iterator function arguments are *value, key* 67 | 68 | EachP is a Parallel implementation of Each and *concurrently* applies the given iterator function to each element of a collection (slice or map). 69 | 70 | 71 | ``` go 72 | // var Each func(func(value interface{}, i interface{}), interface{}) 73 | 74 | var buffer bytes.Buffer 75 | 76 | fn := func(s, i interface{}) { 77 | buffer.WriteString(s.(string)) 78 | } 79 | 80 | s := []string{"a", "b", "c", "d", "e"} 81 | Each(fn, s) 82 | 83 | expect := "abcde" 84 | 85 | e := un.Each(fn, s) 86 | 87 | fmt.Printf("%#v\n", e) //"abcde" 88 | ``` 89 | 90 | Typed Each can be defined using a function type and the *MakeEach* helper. 91 | 92 | Using a Typed Slice 93 | 94 | ``` go 95 | var EachInt func(func(value, i int), []int) 96 | MakeEach(&EachInt) 97 | 98 | var sum int 99 | 100 | fn := func(v, i int) { 101 | sum += v 102 | } 103 | 104 | i := []int{1, 2, 3, 4, 5} 105 | EachInt(fn, i) 106 | 107 | fmt.Printf("%#v\n", sum) //15 108 | ``` 109 | 110 | Using a Typed Map 111 | ``` go 112 | var EachStringInt func(func(key string, value int), map[string]int) 113 | var sum int 114 | 115 | fn := func(v int, k string) { 116 | sum += v 117 | } 118 | 119 | m := map[string]int{"a": 1, "b": 2, "c": 3, "d": 4, "e": 5} 120 | EachStringInt(fn, m) 121 | 122 | fmt.Printf("%#v\n", sum) //15 123 | ``` 124 | 125 | Of note is the ability to close over variables within the calling scope. 126 | 127 | 128 | ### Every ### 129 | --------------------------------------------------------------------------- 130 | 131 | 132 | 133 | 134 | ### Map ### 135 | --------------------------------------------------------------------------- 136 | 137 | ``` go 138 | Map func([]A, func(A) B) []B 139 | ``` 140 | 141 | Applies the given function to each element of a slice, returning a slice of results 142 | 143 | The base Map function accepts interface{} types and returns []interface{} 144 | 145 | ``` go 146 | // Map func(interface{}, func(interface{}) interface{}) []interface{} 147 | 148 | s := []string{"a", "b", "c", "d"} 149 | 150 | fn := func(s interface{}) interface{} { 151 | return s.(string) + "!" 152 | } 153 | 154 | m := un.Map(ToI(s), fn) 155 | fmt.Println(m) //["a!", "b!", "c!", "d!"] 156 | ``` 157 | 158 | Typed Maps can be defined using a function type and the *MakeMap* helper. 159 | 160 | ``` go 161 | Map func([]A, func(A) B) []B 162 | 163 | var SMap func([]string, func(string) string) []string 164 | un.MakeMap(&SMap) 165 | 166 | m := un.SMap(s, fn) 167 | fmt.Println(m) //["a!", "b!", "c!", "d!"] 168 | ``` 169 | 170 | Of note is the return value of Map is a slice of the return type of the applied function. 171 | 172 | 173 | ### Partition ### 174 | --------------------------------------------------------------------------- 175 | 176 | Partition func([]A, func(A) bool) ([]A []A) 177 | 178 | Partition splits a slice or map based on the evaluation of the supplied function 179 | 180 | The base Partition function accepts interface{} types and returns []interface{} 181 | 182 | 183 | ``` go 184 | // Partition func(interface{}, func(interface{}) bool) ([]interface{}, []interface{}) 185 | 186 | s := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} 187 | 188 | fn := func(i interface{}) bool { 189 | return (i.(int) % 2) == 1 190 | } 191 | 192 | odd, even := un.Partition(s, fn) 193 | 194 | fmt.Println(odd) //[1, 3, 5, 7, 9] 195 | fmt.Println(even) //[2, 4, 6, 8, 10] 196 | ``` 197 | 198 | Typed Partitions can be defined using a function type and the *MakePartition* helper. 199 | 200 | ``` go 201 | // Partition func([]A, func(A) bool) ([]A []A) 202 | 203 | var IPartition func([]int, func(int) bool) ([]int, []int) 204 | 205 | un.MakePartition(&IPartition) 206 | 207 | s := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} 208 | 209 | fn := func(i int) bool { 210 | return (i % 2) == 1 211 | } 212 | 213 | odd, even := un.IPartition(s, fn) 214 | 215 | fmt.Println(odd) //[1, 3, 5, 7, 9] 216 | fmt.Println(even) //[2, 4, 6, 8, 10] 217 | ``` 218 | 219 | 220 | Contains returns true if an object is in a slice. 221 | 222 | ``` go 223 | o := "a" 224 | s := []string{"a", "b", "c"} 225 | 226 | b := un.Contains(s, o) 227 | fmt.Println(b) //true 228 | ``` 229 | 230 | 231 | ToI converts a slice of arbitrary type []T into a slice of []interfaces{} 232 | 233 | ``` go 234 | s := []int{1, 1, 3, 5, 8, 13} 235 | i := un.ToI(s) 236 | ``` 237 | 238 | 239 | 240 | 241 | Notes 242 | ------------------------------------------ 243 | 244 | I am aware that the whole idea is not particularly very TheGoWay™, but it is useful as a learning exercise, and it is useful for moving fast and optimising later. 245 | -------------------------------------------------------------------------------- /any.go: -------------------------------------------------------------------------------- 1 | package un 2 | 3 | import ( 4 | "reflect" 5 | ) 6 | 7 | func init() { 8 | MakeAny(&Any) 9 | MakeAny(&AnyInt) 10 | MakeAny(&AnyString) 11 | } 12 | 13 | // Any func(func(A, bool), bool) 14 | // Returns true if all values in the collection (slice or map) pass the predicate truth test 15 | 16 | // var Any func(func(value interface{}) bool, interface{}) bool 17 | var Any func(fn, slice_or_map interface{}) bool 18 | 19 | // AnyInt 20 | // Returns true if all values in a []int pass the predicate truth test 21 | // Predicate function accepts an int and returns a boolean 22 | var AnyInt func(func(value int) bool, []int) bool 23 | 24 | // AnyString 25 | // Returns true if all values in a []string pass the predicate truth test 26 | // Predicate function accepts a string and returns a boolean 27 | var AnyString func(func(value string) bool, []string) bool 28 | 29 | // MakeAny: implements a typed Each function in the form Each func(func(A, B), []A) 30 | func MakeAny(fn interface{}) { 31 | Maker(fn, any) 32 | } 33 | 34 | func any(values []reflect.Value) []reflect.Value { 35 | fn, col := extractArgs(values) 36 | 37 | var ret bool 38 | if col.Kind() == reflect.Map { 39 | ret = anyMap(fn, col) 40 | } 41 | 42 | if col.Kind() == reflect.Slice { 43 | ret = anySlice(fn, col) 44 | } 45 | 46 | return Valueize(reflect.ValueOf(ret)) 47 | } 48 | 49 | func anySlice(fn, s reflect.Value) bool { 50 | for i := 0; i < s.Len(); i++ { 51 | v := s.Index(i) 52 | if ok := callPredicate(fn, v); ok { 53 | return true 54 | } 55 | } 56 | return false 57 | } 58 | 59 | func anyMap(fn, m reflect.Value) bool { 60 | for _, k := range m.MapKeys() { 61 | v := m.MapIndex(k) 62 | if ok := callPredicate(fn, v); ok { 63 | return true 64 | } 65 | } 66 | return false 67 | } 68 | -------------------------------------------------------------------------------- /any_test.go: -------------------------------------------------------------------------------- 1 | package un 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | ) 7 | 8 | func init() { 9 | // suite("Any") 10 | } 11 | 12 | func TestAnySlice(t *testing.T) { 13 | 14 | fn := func(s interface{}) bool { 15 | return true 16 | } 17 | 18 | s := ToI([]int{1, 2, 3, 4, 5}) 19 | result := Any(fn, s) 20 | 21 | equals(t, true, result) 22 | } 23 | 24 | func TestAnyMap(t *testing.T) { 25 | 26 | fn := func(s interface{}) bool { 27 | return true 28 | } 29 | 30 | m := map[string]int{"a": 1, "b": 2, "c": 3, "d": 4, "e": 5} 31 | result := Any(fn, m) 32 | 33 | equals(t, true, result) 34 | } 35 | 36 | func TestAnySliceWithInt(t *testing.T) { 37 | 38 | fn := func(i int) bool { 39 | return i == 3 40 | } 41 | 42 | s := []int{1, 2, 3, 4, 5} 43 | result := AnyInt(fn, s) 44 | 45 | equals(t, true, result) 46 | } 47 | 48 | func TestAnySliceWithString(t *testing.T) { 49 | 50 | fn := func(s string) bool { 51 | return strings.Contains(s, "d") 52 | } 53 | 54 | s := []string{"a!", "b!", "c!", "d!", "e!"} 55 | result := AnyString(fn, s) 56 | 57 | equals(t, true, result) 58 | } 59 | 60 | func TestAnyMapWithInt(t *testing.T) { 61 | fn := func(i interface{}) bool { 62 | return i.(int) == 2 63 | } 64 | 65 | m := map[string]int{"a": 1, "b": 2, "c": 3, "d": 4, "e": 5} 66 | result := Any(fn, m) 67 | 68 | equals(t, true, result) 69 | } 70 | -------------------------------------------------------------------------------- /each.go: -------------------------------------------------------------------------------- 1 | package un 2 | 3 | import ( 4 | "reflect" 5 | "sync" 6 | ) 7 | 8 | func init() { 9 | MakeEach(&Each) 10 | MakeEach(&EachInt) 11 | // MakeEach(&EachString) 12 | MakeEach(&EachStringInt) 13 | MakeEachP(&EachP) 14 | } 15 | 16 | // Each func(func(A, B), []A) 17 | // Applies the given iterator function to each element of a collection (slice or map). 18 | // If the collection is a Slice, the iterator function arguments are *value, index* 19 | // If the collection is a Map, the iterator function arguments are *value, key* 20 | // Iterator functions accept a value, and the index or key is an optional argument. 21 | // Note: each does not return a value, you may want un.Map 22 | // var Each func(func(value, i interface{}), interface{}) 23 | var Each func(fn interface{}, slice_or_map interface{}) 24 | 25 | // EachP Parallel Each 26 | // *Concurrently* applies the given iterator function to each element of a collection (slice or map). 27 | var EachP func(fn interface{}, slice_or_map interface{}) 28 | 29 | // EachInt 30 | // Applies the given iterator function to each element of []int 31 | // Iterator function arguments are *value, index* 32 | var EachInt func(func(value, i int), []int) 33 | 34 | // EachStringInt 35 | // Applies the given iterator function to each element of map[string]int 36 | // Iterator function arguments are *value, key* 37 | var EachStringInt func(func(value int, key string), map[string]int) 38 | 39 | // MakeEach implements a typed Each function in the form Each func(func(A, B), []A) 40 | func MakeEach(fn interface{}) { 41 | Maker(fn, each) 42 | } 43 | 44 | // MakeEachP implements a typed Parallel-Each function in the form EachP func(func(A, B), []A) 45 | func MakeEachP(fn interface{}) { 46 | Maker(fn, eachP) 47 | } 48 | 49 | func each(values []reflect.Value) []reflect.Value { 50 | fn, col := extractArgs(values) 51 | 52 | if col.Kind() == reflect.Map { 53 | eachMap(fn, col) 54 | } 55 | 56 | if col.Kind() == reflect.Slice { 57 | eachSlice(fn, col) 58 | } 59 | 60 | return nil 61 | } 62 | 63 | func eachSlice(fn, s reflect.Value) { 64 | for i := 0; i < s.Len(); i++ { 65 | v := s.Index(i) 66 | eachCall(fn, v, reflect.ValueOf(i)) 67 | } 68 | } 69 | 70 | func eachMap(fn, m reflect.Value) { 71 | for _, k := range m.MapKeys() { 72 | v := m.MapIndex(k) 73 | eachCall(fn, v, k) 74 | } 75 | } 76 | 77 | func eachCall(fn, v, i reflect.Value) { 78 | args := []reflect.Value{v} 79 | if in := fn.Type().NumIn(); in == 2 { 80 | args = append(args, i) 81 | } 82 | fn.Call(args) 83 | } 84 | 85 | func eachP(values []reflect.Value) []reflect.Value { 86 | 87 | fn, col := extractArgs(values) 88 | 89 | if col.Kind() == reflect.Map { 90 | eachMapP(fn, col) 91 | } 92 | 93 | if col.Kind() == reflect.Slice { 94 | eachSliceP(fn, col) 95 | } 96 | 97 | return nil 98 | } 99 | 100 | func eachSliceP(fn, s reflect.Value) { 101 | var done sync.WaitGroup 102 | for i := 0; i < s.Len(); i++ { 103 | v := s.Index(i) 104 | done.Add(1) 105 | go func() { 106 | eachCall(fn, v, reflect.ValueOf(i)) 107 | done.Done() 108 | }() 109 | } 110 | done.Wait() 111 | } 112 | 113 | func eachMapP(fn, m reflect.Value) { 114 | var done sync.WaitGroup 115 | keys := m.MapKeys() 116 | done.Add(len(keys)) 117 | 118 | for _, k := range keys { 119 | v := m.MapIndex(k) 120 | go func(fn, v, k reflect.Value) { 121 | eachCall(fn, v, k) 122 | done.Done() 123 | }(fn, v, k) 124 | } 125 | done.Wait() 126 | } 127 | 128 | // Reference Each Implementation 129 | func refEach(slice []string, fn func(string)) { 130 | for i := 0; i < len(slice); i++ { 131 | fn(slice[i]) 132 | } 133 | } 134 | 135 | // Reference Parallel Each Implementation 136 | func refPEach(slice []string, fn func(string)) { 137 | var done sync.WaitGroup 138 | 139 | for _, s := range slice { 140 | s := s 141 | done.Add(1) 142 | go func() { 143 | fn(s) 144 | done.Done() 145 | }() 146 | } 147 | 148 | done.Wait() 149 | } 150 | -------------------------------------------------------------------------------- /each_test.go: -------------------------------------------------------------------------------- 1 | package un 2 | 3 | import ( 4 | "bytes" 5 | "strconv" 6 | "testing" 7 | ) 8 | 9 | func init() { 10 | } 11 | 12 | func TestEach(t *testing.T) { 13 | var buffer bytes.Buffer 14 | 15 | fn := func(s interface{}) { 16 | buffer.WriteString(s.(string)) 17 | } 18 | 19 | Each(fn, SLICE_STRING) 20 | 21 | expect := "abcdefghijklmnopqrstuvwxyz" 22 | 23 | equals(t, expect, buffer.String()) 24 | } 25 | 26 | func TestEachWithIndex(t *testing.T) { 27 | var buffer bytes.Buffer 28 | 29 | fn := func(s, i interface{}) { 30 | buffer.WriteString(s.(string)) 31 | } 32 | 33 | Each(fn, SLICE_STRING) 34 | 35 | expect := "abcdefghijklmnopqrstuvwxyz" 36 | 37 | equals(t, expect, buffer.String()) 38 | } 39 | 40 | func TestEachWithMap(t *testing.T) { 41 | var buffer bytes.Buffer 42 | 43 | fn := func(v, k interface{}) { 44 | buffer.WriteString(k.(string)) 45 | buffer.WriteString(strconv.Itoa(v.(int))) 46 | } 47 | 48 | Each(fn, MAP_STRING_TO_INT) 49 | 50 | expect := "abcdefghijklmnopqrstuvwxyz1234567891011121314151617181920212223242526" 51 | receive := buffer.String() 52 | 53 | equals(t, len(expect), len(receive)) 54 | } 55 | 56 | func TestEachWithMapValueOnly(t *testing.T) { 57 | 58 | var buffer bytes.Buffer 59 | 60 | fn := func(v interface{}) { 61 | buffer.WriteString(strconv.Itoa(v.(int))) 62 | } 63 | 64 | Each(fn, MAP_STRING_TO_INT) 65 | 66 | expect := "1234567891011121314151617181920212223242526" 67 | receive := buffer.String() 68 | 69 | equals(t, len(expect), len(receive)) 70 | } 71 | 72 | func TestEachStringInt(t *testing.T) { 73 | var receive int 74 | 75 | fn := func(v int, k string) { 76 | receive += v 77 | } 78 | 79 | m := map[string]int{"a": 1, "b": 2, "c": 3, "d": 4, "e": 5} 80 | 81 | EachStringInt(fn, m) 82 | 83 | expect := 15 84 | equals(t, expect, receive) 85 | } 86 | 87 | func TestEachInt(t *testing.T) { 88 | var receive int 89 | 90 | fn := func(v, i int) { 91 | receive += v 92 | } 93 | 94 | EachInt(fn, SLICE_INT) 95 | 96 | expect := 45 97 | equals(t, expect, receive) 98 | } 99 | 100 | func TestEachP(t *testing.T) { 101 | var buffer bytes.Buffer 102 | 103 | ch := make(chan string) 104 | 105 | fn := func(s string) { 106 | ch <- s 107 | } 108 | 109 | go func() { 110 | EachP(fn, SLICE_STRING) 111 | close(ch) 112 | }() 113 | 114 | for s := range ch { 115 | buffer.WriteString(s) 116 | } 117 | 118 | expect := "abcdefghijklmnopqrstuvwxyz" 119 | 120 | equals(t, expect, buffer.String()) 121 | } 122 | 123 | func TestEachPMap(t *testing.T) { 124 | var buffer bytes.Buffer 125 | 126 | ch := make(chan int) 127 | 128 | fn := func(i int) { 129 | ch <- i 130 | } 131 | 132 | go func() { 133 | EachP(fn, MAP_STRING_TO_INT) 134 | close(ch) 135 | }() 136 | 137 | for i := range ch { 138 | buffer.WriteString(strconv.Itoa(i)) 139 | } 140 | 141 | // expect := "abcdefghijklmnopqrstuvwxyz" 142 | expect := "1234567891011121314151617181920212223242526" 143 | receive := buffer.String() 144 | equals(t, len(expect), len(receive)) 145 | } 146 | 147 | func TestRefEach(t *testing.T) { 148 | var buffer bytes.Buffer 149 | 150 | fn := func(s string) { 151 | buffer.WriteString(s) 152 | } 153 | 154 | refEach(SLICE_STRING, fn) 155 | 156 | expect := "abcdefghijklmnopqrstuvwxyz" 157 | 158 | equals(t, expect, buffer.String()) 159 | } 160 | 161 | func TestRefPEach(t *testing.T) { 162 | var buffer bytes.Buffer 163 | 164 | ch := make(chan string) 165 | 166 | fn := func(s string) { 167 | ch <- s 168 | } 169 | 170 | go func() { 171 | refPEach(SLICE_STRING, fn) 172 | close(ch) 173 | }() 174 | 175 | for s := range ch { 176 | buffer.WriteString(s) 177 | } 178 | 179 | expect := "abcdefghijklmnopqrstuvwxyz" 180 | 181 | equals(t, expect, buffer.String()) 182 | } 183 | -------------------------------------------------------------------------------- /every.go: -------------------------------------------------------------------------------- 1 | package un 2 | 3 | import ( 4 | "reflect" 5 | ) 6 | 7 | func init() { 8 | MakeEvery(&Every) 9 | MakeEvery(&EveryInt) 10 | MakeEvery(&EveryString) 11 | } 12 | 13 | // Every func(func(A, bool), bool) 14 | // Returns true if all values in the collection (slice or map) pass the predicate truth test 15 | 16 | // var Every func(func(value interface{}) bool, interface{}) bool 17 | var Every func(fn, slice_or_map interface{}) bool 18 | 19 | // EveryInt 20 | // Returns true if all values in a []int pass the predicate truth test 21 | // Predicate function accepts an int and returns a boolean 22 | var EveryInt func(func(value int) bool, []int) bool 23 | 24 | // EveryString 25 | // Returns true if all values in a []string pass the predicate truth test 26 | // Predicate function accepts a string and returns a boolean 27 | var EveryString func(func(value string) bool, []string) bool 28 | 29 | // MakeEvery: implements a typed Each function in the form Each func(func(A, B), []A) 30 | func MakeEvery(fn interface{}) { 31 | Maker(fn, every) 32 | } 33 | 34 | func every(values []reflect.Value) []reflect.Value { 35 | fn, col := extractArgs(values) 36 | 37 | var ret bool 38 | if col.Kind() == reflect.Map { 39 | ret = everyMap(fn, col) 40 | } 41 | 42 | if col.Kind() == reflect.Slice { 43 | ret = everySlice(fn, col) 44 | } 45 | 46 | return Valueize(reflect.ValueOf(ret)) 47 | } 48 | 49 | func everySlice(fn, s reflect.Value) bool { 50 | for i := 0; i < s.Len(); i++ { 51 | v := s.Index(i) 52 | if ok := callPredicate(fn, v, reflect.ValueOf(i)); !ok { 53 | return false 54 | } 55 | } 56 | return true 57 | } 58 | 59 | func everyMap(fn, m reflect.Value) bool { 60 | for _, k := range m.MapKeys() { 61 | v := m.MapIndex(k) 62 | if ok := callPredicate(fn, v); !ok { 63 | return false 64 | } 65 | } 66 | return true 67 | } 68 | -------------------------------------------------------------------------------- /every_test.go: -------------------------------------------------------------------------------- 1 | package un 2 | 3 | import "testing" 4 | 5 | func init() { 6 | // suite("Every") 7 | } 8 | 9 | func TestEverySlice(t *testing.T) { 10 | title("Slice") 11 | 12 | fn := func(s interface{}) bool { 13 | return true 14 | } 15 | 16 | s := ToI([]int{1, 2, 3, 4, 5}) 17 | result := Every(fn, s) 18 | 19 | equals(t, true, result) 20 | } 21 | 22 | func TestEveryMap(t *testing.T) { 23 | title("Map") 24 | 25 | fn := func(s interface{}) bool { 26 | return true 27 | } 28 | 29 | m := map[string]int{"a": 1, "b": 2, "c": 3, "d": 4, "e": 5} 30 | result := Every(fn, m) 31 | 32 | equals(t, true, result) 33 | } 34 | 35 | func TestEverySliceWithInt(t *testing.T) { 36 | 37 | fn := func(i int) bool { 38 | return i <= 5 39 | } 40 | 41 | s := []int{1, 2, 3, 4, 5} 42 | result := EveryInt(fn, s) 43 | 44 | equals(t, true, result) 45 | } 46 | 47 | func TestEverySliceWithString(t *testing.T) { 48 | 49 | fn := func(s string) bool { 50 | // return strings.Contains(s, "!") 51 | return true 52 | } 53 | 54 | s := []string{"a!", "b!", "c!", "d!", "e!"} 55 | result := EveryString(fn, s) 56 | 57 | equals(t, true, result) 58 | } 59 | 60 | func TestEveryMapWithInt(t *testing.T) { 61 | title("Map With Int") 62 | fn := func(i interface{}) bool { 63 | return i.(int) <= 5 64 | } 65 | 66 | m := map[string]int{"a": 1, "b": 2, "c": 3, "d": 4, "e": 5} 67 | result := Every(fn, m) 68 | 69 | equals(t, true, result) 70 | } 71 | -------------------------------------------------------------------------------- /indexof.go: -------------------------------------------------------------------------------- 1 | package un 2 | -------------------------------------------------------------------------------- /indexof_test.go: -------------------------------------------------------------------------------- 1 | package un 2 | -------------------------------------------------------------------------------- /map.go: -------------------------------------------------------------------------------- 1 | package un 2 | 3 | import "reflect" 4 | 5 | func init() { 6 | MakeMap(&Map) 7 | MakeMap(&MapString) 8 | MakeMap(&MapInt) 9 | MakePMap(&MapP) 10 | MakePMap(&MapPString) 11 | // MakeMap(&MapStringToBool) 12 | } 13 | 14 | // Map func(func(A) C, []A) []C 15 | // Applies the given iterator function to each element of a collection (slice or map) and returns a new slice of the computed results. 16 | // If the collection is a Slice, the iterator function arguments are *value, index* 17 | // If the collection is a Map, the iterator function arguments are *value, key* 18 | // Iterator functions accept a value, and the index or key is an optional argument. 19 | var Map func(interface{}, interface{}) []interface{} 20 | 21 | // Applies the given iterator function to each element of a []string and returns a new []string of the computed results. 22 | var MapString func(func(string) string, []string) []string 23 | 24 | // Applies the given iterator function to each element of a []int and returns a new []int of the computed results. 25 | var MapInt func(func(int) int, []int) []int 26 | 27 | // Applies the given iterator function to each element of a collection (slice or map) and returns a new slice of the computed results. 28 | var MapP func(interface{}, interface{}, ...int) []interface{} 29 | 30 | // Applies the given iterator function to each element of a []string and returns a new []string of the computed results. 31 | //
Uses a Worker Pool using either the global worker value (un.SetWorker) or as an optional parameter
32 | //MapPString(fn, col, n)
33 | var MapPString func(func(string) string, []string, ...int) []string 34 | 35 | // var MapStringToBool func([]string, func(string) bool) []bool 36 | 37 | // MakeMap implements a typed Map function in the form Map func(func(A) C, []A) []C 38 | func MakeMap(fn interface{}) { 39 | Maker(fn, mapImpl) 40 | } 41 | 42 | // MakePMap implements a typed Parallel Map function in the form Map func(func(A) C, []A) []C 43 | func MakePMap(fn interface{}) { 44 | Maker(fn, mapPImpl) 45 | } 46 | 47 | func mapImpl(values []reflect.Value) []reflect.Value { 48 | 49 | fn, col := extractArgs(values) 50 | 51 | ret := makeSlice(fn, col.Len()) 52 | 53 | // if list.Kind() == reflect.Map { 54 | // ret = everyMap(fn, list) 55 | // } 56 | 57 | if col.Kind() == reflect.Slice { 58 | ret = mapSlice(fn, col) 59 | } 60 | 61 | return []reflect.Value{ret} 62 | } 63 | 64 | func mapSlice(fn, col reflect.Value) reflect.Value { 65 | ret := makeSlice(fn, col.Len()) 66 | 67 | for i := 0; i < col.Len(); i++ { 68 | e := col.Index(i) 69 | r := fn.Call([]reflect.Value{e}) 70 | ret.Index(i).Set(r[0]) 71 | } 72 | return ret 73 | } 74 | 75 | func mapWorker(fn reflect.Value, job chan []reflect.Value, res reflect.Value) { 76 | for { 77 | v, ok := <-job 78 | if !ok { 79 | break 80 | } 81 | if len(v) > 0 { 82 | r := fn.Call(v) 83 | res.Send(r[0]) 84 | } 85 | } 86 | } 87 | 88 | func mapPImpl(values []reflect.Value) []reflect.Value { 89 | fn, col := extractArgs(values) 90 | 91 | workers := 1 //workers 92 | if len(values) == 3 { 93 | if l := values[2].Len(); l == 1 { 94 | workers = int(values[2].Index(0).Int()) 95 | } 96 | } 97 | 98 | t := fn.Type().Out(0) 99 | job, res := makeWorkerChans(t) 100 | 101 | ret := makeSlice(fn, col.Len()) 102 | 103 | for i := 1; i <= workers; i++ { 104 | go mapWorker(fn, job, res) 105 | } 106 | 107 | if col.Kind() == reflect.Slice { 108 | mapPSlice(job, col) 109 | } 110 | 111 | if col.Kind() == reflect.Map { 112 | mapPMap(job, col) 113 | } 114 | 115 | close(job) 116 | 117 | for i := 0; i < col.Len(); i++ { 118 | v, ok := res.Recv() 119 | if !ok { 120 | break 121 | } 122 | ret.Index(i).Set(v) 123 | } 124 | 125 | return []reflect.Value{ret} 126 | } 127 | 128 | func mapPSlice(job chan []reflect.Value, col reflect.Value) { 129 | for i := 0; i < col.Len(); i++ { 130 | e := col.Index(i) 131 | job <- []reflect.Value{e} 132 | } 133 | } 134 | 135 | func mapPMap(job chan []reflect.Value, col reflect.Value) { 136 | for _, k := range col.MapKeys() { 137 | v := col.MapIndex(k) 138 | job <- []reflect.Value{v, k} 139 | } 140 | } 141 | 142 | func refMapMap(m map[string]int, fn func(string, int) string) []string { 143 | ret := make([]string, 0, len(m)) 144 | 145 | for k, v := range m { 146 | ret = append(ret, fn(k, v)) 147 | } 148 | return ret 149 | } 150 | -------------------------------------------------------------------------------- /map_test.go: -------------------------------------------------------------------------------- 1 | package un 2 | 3 | import ( 4 | "runtime" 5 | "strconv" 6 | "strings" 7 | "testing" 8 | ) 9 | 10 | func TestMapWithSliceInterface(t *testing.T) { 11 | fn := func(s interface{}) interface{} { 12 | return s.(string) + "!" 13 | } 14 | receive := Map(fn, SLICE_STRING) 15 | 16 | expect := "a!" 17 | equals(t, expect, receive[0]) 18 | } 19 | 20 | func TestMapString(t *testing.T) { 21 | fn := func(s string) string { 22 | return s + "!" 23 | } 24 | 25 | receive := MapString(fn, SLICE_STRING) 26 | 27 | expect := "a!" 28 | equals(t, expect, receive[0]) 29 | } 30 | 31 | func TestMapInt(t *testing.T) { 32 | fn := func(i int) int { 33 | return i + 1 34 | } 35 | 36 | receive := MapInt(fn, SLICE_INT) 37 | 38 | expect := 1 39 | equals(t, expect, receive[0]) 40 | } 41 | 42 | func TestMakePMapWithSlice(t *testing.T) { 43 | runtime.GOMAXPROCS(runtime.NumCPU()) 44 | fn := func(s string) string { 45 | return s + "!" 46 | } 47 | receive := MapPString(fn, SLICE_STRING) 48 | 49 | assert(t, strings.Contains(receive[0], "!"), "should contain !") 50 | } 51 | 52 | func TestMakePMapWithMap(t *testing.T) { 53 | runtime.GOMAXPROCS(runtime.NumCPU()) 54 | 55 | fn := func(v, k interface{}) interface{} { 56 | return k.(string) + strconv.Itoa(v.(int)) + "!" 57 | } 58 | 59 | receive := MapP(fn, MAP_STRING_TO_INT, 20) 60 | 61 | display(receive) 62 | // assert(t, strings.Contains(receive[0], "!"), "should contain !") 63 | } 64 | -------------------------------------------------------------------------------- /none.go: -------------------------------------------------------------------------------- 1 | package un 2 | 3 | import ( 4 | "reflect" 5 | ) 6 | 7 | func init() { 8 | MakeNone(&None) 9 | MakeNone(&NoneInt) 10 | MakeNone(&NoneString) 11 | } 12 | 13 | // None func(func(A, bool), bool) 14 | // Returns true if all values in the collection (slice or map) pass the predicate truth test 15 | 16 | // var None func(func(value interface{}) bool, interface{}) bool 17 | var None func(fn, slice_or_map interface{}) bool 18 | 19 | // NoneInt 20 | // Returns true if all values in a []int pass the predicate truth test 21 | // Predicate function accepts an int and returns a boolean 22 | var NoneInt func(func(value int) bool, []int) bool 23 | 24 | // NoneString 25 | // Returns true if all values in a []string pass the predicate truth test 26 | // Predicate function accepts a string and returns a boolean 27 | var NoneString func(func(value string) bool, []string) bool 28 | 29 | // MakeNone: implements a typed Each function in the form Each func(func(A, B), []A) 30 | func MakeNone(fn interface{}) { 31 | Maker(fn, none) 32 | } 33 | 34 | func none(values []reflect.Value) []reflect.Value { 35 | fn, col := extractArgs(values) 36 | 37 | var ret bool 38 | if col.Kind() == reflect.Map { 39 | ret = noneMap(fn, col) 40 | } 41 | 42 | if col.Kind() == reflect.Slice { 43 | ret = noneSlice(fn, col) 44 | } 45 | 46 | return Valueize(reflect.ValueOf(ret)) 47 | } 48 | 49 | func noneSlice(fn, s reflect.Value) bool { 50 | for i := 0; i < s.Len(); i++ { 51 | v := s.Index(i) 52 | if ok := callPredicate(fn, v); ok { 53 | return false 54 | } 55 | } 56 | return true 57 | } 58 | 59 | func noneMap(fn, m reflect.Value) bool { 60 | for _, k := range m.MapKeys() { 61 | v := m.MapIndex(k) 62 | if ok := callPredicate(fn, v); ok { 63 | return false 64 | } 65 | } 66 | return true 67 | } 68 | -------------------------------------------------------------------------------- /none_test.go: -------------------------------------------------------------------------------- 1 | package un 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | ) 7 | 8 | func init() { 9 | } 10 | 11 | func TestNoneSlice(t *testing.T) { 12 | 13 | fn := func(s interface{}) bool { 14 | return false 15 | } 16 | 17 | s := ToI([]int{1, 2, 3, 4, 5}) 18 | result := None(fn, s) 19 | 20 | equals(t, true, result) 21 | } 22 | 23 | func TestNoneMap(t *testing.T) { 24 | 25 | fn := func(s interface{}) bool { 26 | return false 27 | } 28 | 29 | m := map[string]int{"a": 1, "b": 2, "c": 3, "d": 4, "e": 5} 30 | result := None(fn, m) 31 | 32 | equals(t, true, result) 33 | } 34 | 35 | func TestNoneSliceWithInt(t *testing.T) { 36 | 37 | fn := func(i int) bool { 38 | return i > 10 39 | } 40 | 41 | s := []int{1, 2, 3, 4, 5} 42 | result := NoneInt(fn, s) 43 | 44 | equals(t, true, result) 45 | } 46 | 47 | func TestNoneSliceWithString(t *testing.T) { 48 | 49 | fn := func(s string) bool { 50 | return strings.Contains(s, "z") 51 | } 52 | 53 | s := []string{"a!", "b!", "c!", "d!", "e!"} 54 | result := NoneString(fn, s) 55 | 56 | equals(t, true, result) 57 | } 58 | 59 | func TestNoneMapWithInt(t *testing.T) { 60 | fn := func(i interface{}) bool { 61 | return i.(int) >= 211 62 | } 63 | 64 | m := map[string]int{"a": 1, "b": 2, "c": 3, "d": 4, "e": 5} 65 | result := None(fn, m) 66 | 67 | equals(t, true, result) 68 | } 69 | -------------------------------------------------------------------------------- /partition.go: -------------------------------------------------------------------------------- 1 | package un 2 | 3 | import "reflect" 4 | 5 | func init() { 6 | MakePartition(&Partition) 7 | MakePartition(&PartitionInt) 8 | // MakePartition(&PartitionString) 9 | // MakePartition(&PartitionStringInt) 10 | // MakePartitionP(&PartitionP) 11 | } 12 | 13 | // Partition func(func(A, B) bool, []A []A) 14 | // Applies the given iterator function to partition element of a collection (slice or map). 15 | // If the collection is a Slice, the iterator function arguments are *value, index* 16 | // If the collection is a Map, the iterator function arguments are *value, key* 17 | // Iterator functions accept a value, and the index or key is an optional argument. 18 | // Note: partition does not return a value, you may want un.Map 19 | // var Partition func(func(value, i interface{}), interface{}) 20 | var Partition func(fn interface{}, slice_or_map interface{}) ([]interface{}, []interface{}) 21 | 22 | // var Partition func(interface{}, func(interface{}) bool) ([]interface{}, []interface{}) 23 | 24 | // // PartitionP Parallel Partition 25 | // // *Concurrently* applies the given iterator function to partition element of a collection (slice or map). 26 | // var PartitionP func(fn interface{}, slice_or_map interface{}) 27 | 28 | // // PartitionInt 29 | // // Applies the given iterator function to partition element of []int 30 | // // Iterator function arguments are *value, index* 31 | var PartitionInt func(func(value, i int), []int) ([]int, []int) 32 | 33 | // // PartitionStringInt 34 | // // Applies the given iterator function to partition element of map[string]int 35 | // // Iterator function arguments are *value, key* 36 | // var PartitionStringInt func(func(value int, key string), map[string]int) 37 | 38 | // MakePartition implements a typed Partition function in the form Partition func(func(A, B), []A) 39 | func MakePartition(fn interface{}) { 40 | Maker(fn, partition) 41 | } 42 | 43 | type partitioner struct { 44 | fn reflect.Value 45 | col reflect.Value 46 | t reflect.Value 47 | f reflect.Value 48 | } 49 | 50 | func partition(values []reflect.Value) []reflect.Value { 51 | 52 | fn, col := extractArgs(values) 53 | kind := values[1].Kind() 54 | 55 | p := newPartitioner(fn, col, kind) 56 | 57 | return p.partition() 58 | } 59 | 60 | func newPartitioner(fn, col reflect.Value, kind reflect.Kind) *partitioner { 61 | t, f := makePartitions(col, kind) 62 | return &partitioner{fn: fn, col: col, t: t, f: f} 63 | } 64 | 65 | func (p *partitioner) partition() []reflect.Value { 66 | 67 | switch { 68 | case p.isSlice(): 69 | p.partitionSlice() 70 | case p.isMap(): 71 | p.partitionMap() 72 | } 73 | return []reflect.Value{p.t, p.f} 74 | } 75 | 76 | func (p *partitioner) isSlice() bool { 77 | return p.col.Kind() == reflect.Slice 78 | } 79 | 80 | func (p *partitioner) isMap() bool { 81 | return p.col.Kind() == reflect.Map 82 | } 83 | 84 | func (p *partitioner) partitionSlice() { 85 | for i := 0; i < p.col.Len(); i++ { 86 | val := p.col.Index(i) 87 | idx := reflect.ValueOf(i) 88 | p.partitionate(val, idx) 89 | } 90 | } 91 | 92 | func (p *partitioner) partitionMap() { 93 | for _, key := range p.col.MapKeys() { 94 | val := p.col.MapIndex(key) 95 | p.partitionate(val, key) 96 | } 97 | } 98 | 99 | func (p *partitioner) partitionate(val, idx_or_key reflect.Value) { 100 | if ok := callPredicate(p.fn, val, idx_or_key); ok { 101 | p.t = reflect.Append(p.t, val) 102 | } else { 103 | p.f = reflect.Append(p.f, val) 104 | } 105 | } 106 | 107 | func makePartitions(col reflect.Value, kind reflect.Kind) (reflect.Value, reflect.Value) { 108 | var t, f reflect.Value 109 | 110 | if kind == reflect.Interface { 111 | t = reflect.ValueOf(make([]interface{}, 0)) 112 | f = reflect.ValueOf(make([]interface{}, 0)) 113 | } else { 114 | t = reflect.MakeSlice(col.Type(), 0, 0) 115 | f = reflect.MakeSlice(col.Type(), 0, 0) 116 | } 117 | return t, f 118 | } 119 | -------------------------------------------------------------------------------- /partition_test.go: -------------------------------------------------------------------------------- 1 | package un 2 | 3 | import "testing" 4 | 5 | func init() { 6 | } 7 | 8 | func TestPartitionWithSliceInterface(t *testing.T) { 9 | 10 | fn := func(s interface{}) bool { 11 | return true 12 | } 13 | 14 | receive, _ := Partition(fn, SLICE_STRING) 15 | 16 | expect := SLICE_STRING 17 | equals(t, ToI(expect), receive) 18 | } 19 | 20 | func TestPartitionWithMapInterface(t *testing.T) { 21 | 22 | fn := func(s interface{}) bool { 23 | return true 24 | } 25 | 26 | receive, _ := Partition(fn, MAP_STRING_TO_INT) 27 | 28 | expect := MAP_STRING_TO_INT 29 | equals(t, len(expect), len(receive)) 30 | 31 | display(receive) 32 | } 33 | 34 | func TestPartitionWithSliceInt(t *testing.T) { 35 | 36 | fn := func(i int) bool { 37 | return i < 5 38 | } 39 | 40 | under, over := Partition(fn, SLICE_INT) 41 | 42 | equals(t, 5, len(under)) 43 | equals(t, 5, len(over)) 44 | 45 | equals(t, 0, under[0]) 46 | equals(t, 5, over[0]) 47 | } 48 | -------------------------------------------------------------------------------- /src/underscore.go.old: -------------------------------------------------------------------------------- 1 | package __ 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | func init() { 9 | fmt.Println() 10 | MakeContains(&Contains) 11 | MakeContains(&StringContains) 12 | 13 | MakeMap(&Map) 14 | MakeMap(&MapString) 15 | MakeMap(&MapInt) 16 | MakeMap(&MapStringToBool) 17 | 18 | MakePartition(&Partition) 19 | MakePartition(&PartitionInt) 20 | 21 | MakeReduce(&ReduceInt) 22 | 23 | MakeReduceR(&ReduceRInt) 24 | } 25 | 26 | 27 | /** 28 | Map func([]A, func(A) B) []B 29 | **/ 30 | 31 | var Map func(interface{}, func(interface{}) interface{}) []interface{} 32 | 33 | var MapString func([]string, func(string) string) []string 34 | 35 | var MapInt func([]int, func(int) int) []int 36 | 37 | var MapStringToBool func([]string, func(string) bool) []bool 38 | 39 | 40 | /** 41 | Partition func([]A, func(A) bool) ([]A []A) 42 | **/ 43 | 44 | var Partition func(interface{}, func(interface{}) bool) ([]interface{}, []interface{}) 45 | 46 | var PartitionInt func([]int, func(int) bool) ([]int, []int) 47 | 48 | var PartitionString func([]string, func(string) bool) ([]string, []string) 49 | 50 | 51 | var Contains func(interface{}, interface{}) bool 52 | 53 | var StringContains func([]string, string) bool 54 | 55 | 56 | 57 | var ReduceInt func([]int, func(int, int) int, int) int 58 | 59 | var ReduceRInt func([]int, func(int, int) int, int) int 60 | 61 | 62 | 63 | 64 | func Maker(wrapper interface{}, fn func(args []reflect.Value) (results []reflect.Value)) { 65 | wrapperFn := reflect.ValueOf(wrapper).Elem() 66 | v := reflect.MakeFunc(wrapperFn.Type(), fn) 67 | wrapperFn.Set(v) 68 | } 69 | 70 | func MakeContains(fn interface{}) { 71 | Maker(fn, _contains) 72 | } 73 | 74 | func MakeMap(fn interface{}) { 75 | Maker(fn, _map) 76 | } 77 | 78 | func MakePartition(fn interface{}) { 79 | Maker(fn, _partition) 80 | } 81 | 82 | func MakeReduce(fn interface{}) { 83 | Maker(fn, _reduce) 84 | } 85 | 86 | func MakeReduceR(fn interface{}) { 87 | Maker(fn, _reduceR) 88 | } 89 | 90 | func ToI(slice interface{}) []interface{} { 91 | s := reflect.ValueOf(slice) 92 | if s.Kind() != reflect.Slice { 93 | panic("ToInterface expects a slice type") 94 | } 95 | 96 | ret := make([]interface{}, s.Len()) 97 | 98 | for i := 0; i < s.Len(); i++ { 99 | ret[i] = s.Index(i).Interface() 100 | } 101 | return ret 102 | } 103 | 104 | 105 | func _contains(values []reflect.Value) []reflect.Value { 106 | 107 | v := iToValue(values[0]) 108 | o := values[1].Interface() 109 | 110 | for i := 0; i < v.Len(); i++ { 111 | e := v.Index(i).Interface() 112 | if e == o { 113 | return wrap(reflect.ValueOf(true)) 114 | } 115 | } 116 | return wrap(reflect.ValueOf(false)) 117 | } 118 | 119 | func _map(values []reflect.Value) []reflect.Value { 120 | 121 | v := iToValue(values[0]) 122 | fn := values[1] 123 | 124 | var ret reflect.Value 125 | 126 | outT := reflect.SliceOf(fn.Type().Out(0)) 127 | ret = reflect.MakeSlice(outT, v.Len(), v.Len()) 128 | 129 | for i := 0; i < v.Len(); i++ { 130 | e := v.Index(i) 131 | r := fn.Call([]reflect.Value{e}) 132 | ret.Index(i).Set(r[0]) 133 | } 134 | 135 | return []reflect.Value{ret} 136 | } 137 | 138 | func _partition(values []reflect.Value) []reflect.Value { 139 | slice := iToValue(values[0]) 140 | fn := values[1] 141 | 142 | var t, f reflect.Value 143 | 144 | if values[0].Kind() == reflect.Interface { 145 | t = reflect.ValueOf(make([]interface{},0)) 146 | f = reflect.ValueOf(make([]interface{},0)) 147 | } else { 148 | t = reflect.MakeSlice(slice.Type(), 0, 0) 149 | f = reflect.MakeSlice(slice.Type(), 0, 0) 150 | } 151 | 152 | for i := 0; i < slice.Len(); i++ { 153 | e := slice.Index(i) 154 | r := fn.Call([]reflect.Value{e}) 155 | if r[0].Bool() { 156 | t = reflect.Append(t, e) 157 | } else { 158 | f = reflect.Append(f, e) 159 | } 160 | } 161 | return []reflect.Value{t, f} 162 | } 163 | 164 | 165 | func _reduce(values []reflect.Value) []reflect.Value { 166 | slice := values[0] 167 | fn := values[1] 168 | ret := values[2] 169 | 170 | for i := 0; i < slice.Len(); i++ { 171 | e := slice.Index(i) 172 | r := fn.Call([]reflect.Value{ret, e}) 173 | ret = r[0] 174 | } 175 | 176 | return wrap(ret) 177 | } 178 | 179 | func _reduceR(values []reflect.Value) []reflect.Value { 180 | slice := values[0] 181 | fn := values[1] 182 | ret := values[2] 183 | 184 | for i := slice.Len()-1; i >= 0; i-- { 185 | e := slice.Index(i) 186 | r := fn.Call([]reflect.Value{ret, e}) 187 | ret = r[0] 188 | } 189 | 190 | return wrap(ret) 191 | } 192 | 193 | func wrap(v reflect.Value) []reflect.Value { 194 | return []reflect.Value{v} 195 | } 196 | 197 | func iToValue(v reflect.Value) reflect.Value { 198 | if v.Kind() == reflect.Interface { 199 | return reflect.ValueOf(v.Interface()) 200 | } 201 | return v 202 | } 203 | 204 | 205 | 206 | /** 207 | Reference Implementations Follow 208 | **/ 209 | func reduce(slice []int, fn func(int, int) int, initial int) int { 210 | ret := initial 211 | 212 | for i := 0; i < len(slice); i++ { 213 | e := slice[i] 214 | ret = fn(ret, e) 215 | } 216 | 217 | return ret 218 | } 219 | 220 | func partition (slice []int, fn func(int) bool) ([]int, []int) { 221 | a := []int{} 222 | b := []int{} 223 | 224 | for i := 0; i < len(slice); i++ { 225 | e := slice[i] 226 | if fn(e) { 227 | a = append(a, e) 228 | } else { 229 | b = append(b, e) 230 | } 231 | } 232 | 233 | return a, b 234 | } 235 | 236 | // avoids name collision with map 237 | func collect(slice []string, fn func(string) string) []string { 238 | ret := make([]string, len(slice), len(slice)) 239 | 240 | for i := 0; i < len(slice); i++ { 241 | ret[i] = fn(slice[i]) 242 | } 243 | 244 | return ret 245 | } 246 | 247 | 248 | func collectMap(m map[string]int, fn func(string, int) string) []string { 249 | ret := make([]string, 0, len(m)) 250 | 251 | for k, v := range m { 252 | ret = append(ret, fn(k, v)) 253 | } 254 | fmt.Println(ret) 255 | return ret 256 | } 257 | 258 | -------------------------------------------------------------------------------- /src/underscore_test.go.old: -------------------------------------------------------------------------------- 1 | package __ 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "testing" 7 | "time" 8 | ) 9 | 10 | var SLICE_STRING = []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"} 11 | 12 | var SLICE_INT = []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} 13 | 14 | var MAP = map[string]int{"a":1,"b":2,"c":3,"d":4,"e":5,"f":6,"g":7,"h":8,"i":9,"j":10,"k":11,"l":12,"m":13,"n":14,"o":15,"p":16,"q":17,"r":18,"s":19,"t":20,"u":21,"v":22,"w":23,"x":24,"y":25,"z":26} 15 | 16 | 17 | func TestContains(t *testing.T) { 18 | in := "a" 19 | out := "!" 20 | 21 | if b := Contains(SLICE_STRING, in); b != true { 22 | t.Error("Slice should contain ", in) 23 | } 24 | 25 | if b := Contains(SLICE_STRING, out); b != false { 26 | t.Error("Slice should not contain ", out) 27 | } 28 | } 29 | 30 | func TestMapString(t *testing.T) { 31 | fn := func(s string) string { 32 | return s + "!" 33 | } 34 | 35 | m := MapString(SLICE_STRING, fn) 36 | 37 | if m[0] != "a!" { 38 | t.Error("First element should == a!") 39 | } 40 | } 41 | 42 | func TestMapInt(t *testing.T) { 43 | fn := func(i int) int { 44 | return i + 1 45 | } 46 | 47 | m := MapInt(SLICE_INT, fn) 48 | 49 | if i := m[0]; i != 2 { 50 | t.Error("Expected 2; Recieved ", i) 51 | } 52 | } 53 | 54 | 55 | func TestMapWithInterface(t *testing.T) { 56 | fn := func(s interface{}) interface{} { 57 | return s.(string) + "!" 58 | } 59 | m := Map(ToI(SLICE_STRING), fn) 60 | if m[0] != "a!" { 61 | t.Error("First element should == a!") 62 | } 63 | } 64 | 65 | 66 | func TestMapWithMaps(t *testing.T) { 67 | fn := func(s string, i int) string { 68 | n := strconv.Itoa(i) 69 | return s + n 70 | } 71 | 72 | m := collectMap(MAP, fn) 73 | fmt.Println(m) 74 | if m[0] != "a!" { 75 | t.Error("First element should == a!") 76 | } 77 | } 78 | 79 | 80 | func TestMapMapStringToBool(t *testing.T) { 81 | b := MapStringToBool(SLICE_STRING, func(s string) bool { 82 | return s == "z" 83 | }) 84 | 85 | if b[0] { 86 | t.Error("Expected false; Received true") 87 | } 88 | 89 | if !b[len(b)-1] { 90 | t.Error("Expected true; Received false") 91 | } 92 | } 93 | 94 | func TestPartition(t *testing.T) { 95 | slice := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} 96 | 97 | fn := func(i interface{}) bool { 98 | return (i.(int) % 2) == 1 99 | } 100 | 101 | odd, even := Partition(slice, fn) 102 | 103 | if odd[0] != 1 { 104 | t.Error("First element should == 1") 105 | } 106 | 107 | if even[0] != 2 { 108 | t.Error("First element should == 2") 109 | } 110 | } 111 | 112 | func TestPartitionInt(t *testing.T) { 113 | slice := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} 114 | 115 | fn := func(i int) bool { 116 | return (i % 2) == 1 117 | } 118 | 119 | odd, even := PartitionInt(slice, fn) 120 | 121 | if odd[0] != 1 { 122 | t.Error("First element should == 1") 123 | } 124 | 125 | if even[0] != 2 { 126 | t.Error("First element should == 2") 127 | } 128 | } 129 | 130 | 131 | func TestReduce(t *testing.T) { 132 | slice := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} 133 | 134 | fn := func(m, e int) int { 135 | return m + e 136 | } 137 | 138 | result := ReduceInt(slice, fn, 0) 139 | 140 | if result != 55 { 141 | t.Error("Expected 55 Received: ", result) 142 | } 143 | } 144 | 145 | func TestReduceR(t *testing.T) { 146 | slice := []int{1, 2, 3, 4, 5} 147 | 148 | fn := func(m, e int) int { 149 | return m - e 150 | } 151 | result := ReduceRInt(slice, fn, 15) 152 | 153 | if result != 0 { 154 | t.Error("Expected 0 Received: ", result) 155 | } 156 | } 157 | 158 | 159 | 160 | func contains(slice []string, s string) bool { 161 | for _, e := range slice { 162 | if e == s { 163 | return true 164 | } 165 | } 166 | return false 167 | } 168 | 169 | func with_types(count int) { 170 | in := "z" 171 | start := time.Now() 172 | 173 | for i := 0; i < count; i++ { 174 | contains(SLICE_STRING, in) 175 | } 176 | 177 | elapsed := time.Since(start) 178 | fmt.Println("Typed Contains: ", elapsed) 179 | } 180 | 181 | func with_interface(count int) { 182 | in := "z" 183 | start := time.Now() 184 | 185 | for i := 0; i < count; i++ { 186 | Contains(SLICE_STRING, in) 187 | } 188 | 189 | elapsed := time.Since(start) 190 | fmt.Println("Interface Contains: ", elapsed) 191 | } 192 | 193 | func with_magic(count int) { 194 | in := "z" 195 | start := time.Now() 196 | 197 | for i := 0; i < count; i++ { 198 | StringContains(SLICE_STRING, in) 199 | } 200 | 201 | elapsed := time.Since(start) 202 | fmt.Println("StringContains: ", elapsed) 203 | } 204 | 205 | 206 | func TestBench(t *testing.T) { 207 | count := 10000 208 | with_types(count) 209 | with_interface(count) 210 | with_magic(count) 211 | } 212 | -------------------------------------------------------------------------------- /underscore.go: -------------------------------------------------------------------------------- 1 | package un 2 | 3 | import ( 4 | "reflect" 5 | ) 6 | 7 | func init() { 8 | } 9 | 10 | var workers int = 6 11 | 12 | // Maker takes a function pointer (fn) and implements it with the given reflection-based function implementation 13 | // Internally uses reflect.MakeFunc 14 | func Maker(fn interface{}, impl func(args []reflect.Value) (results []reflect.Value)) { 15 | fnV := reflect.ValueOf(fn).Elem() 16 | fnI := reflect.MakeFunc(fnV.Type(), impl) 17 | fnV.Set(fnI) 18 | } 19 | 20 | // ToI takes a slice and converts it to type []interface[] 21 | func ToI(slice interface{}) []interface{} { 22 | s := reflect.ValueOf(slice) 23 | if s.Kind() != reflect.Slice { 24 | panic("ToInterface expects a slice type") 25 | } 26 | 27 | ret := make([]interface{}, s.Len()) 28 | 29 | for i := 0; i < s.Len(); i++ { 30 | ret[i] = s.Index(i).Interface() 31 | } 32 | return ret 33 | } 34 | 35 | // Valueize takes a number of arguments and returns them as []reflect.Value 36 | func Valueize(values ...interface{}) []reflect.Value { 37 | ret := make([]reflect.Value, len(values)) 38 | 39 | for i := 0; i < len(values); i++ { 40 | v := values[i] 41 | if t := reflect.TypeOf(v).String(); t == "reflect.Value" { 42 | ret[i] = v.(reflect.Value) 43 | } else { 44 | ret[i] = reflect.ValueOf(v) 45 | } 46 | } 47 | 48 | return ret 49 | } 50 | 51 | // SetWorkers sets the number of workers used by the worker pools 52 | //This is a global default value
53 | //If different worker pool sizes are required, use the optional worker argument when calling Parallel Implementations
54 | func SetWorkers(w int) { 55 | workers = w 56 | } 57 | 58 | // extractArgs pulls the arguments from a []reflect.Value and converts as appropriate to underlying types 59 | func extractArgs(values []reflect.Value) (reflect.Value, reflect.Value) { 60 | fn := interfaceToValue(values[0]) 61 | col := interfaceToValue(values[1]) 62 | return fn, col 63 | } 64 | 65 | // interfaceToValue converts a value of interface{} to a value of Interface() 66 | // That is, converts to the underlying type of the reflect.Value 67 | func interfaceToValue(v reflect.Value) reflect.Value { 68 | if v.Kind() == reflect.Interface { 69 | return reflect.ValueOf(v.Interface()) 70 | } 71 | return v 72 | } 73 | 74 | // makeSlice makes a slice of the Output type of the supplied function, and of the specifed capacity 75 | func makeSlice(fn reflect.Value, len int) reflect.Value { 76 | t := reflect.SliceOf(fn.Type().Out(0)) 77 | return reflect.MakeSlice(t, len, len) 78 | } 79 | 80 | // makeWorkerChans makes a buffered channel of the specified type 81 | func makeWorkerChans(t reflect.Type) (chan []reflect.Value, reflect.Value) { 82 | // display(reflect.TypeOf([]reflect.Value{})) 83 | // job := reflect.MakeChan(reflect.ChanOf(reflect.BothDir, reflect.TypeOf(&channeller{})), 100) 84 | // job := reflect.MakeChan(reflect.ChanOf(reflect.BothDir, reflect.TypeOf([]reflect.Value{})), 100) 85 | job := make(chan []reflect.Value) 86 | res := reflect.MakeChan(reflect.ChanOf(reflect.BothDir, t), 100) 87 | return job, res 88 | } 89 | 90 | func callPredicate(fn reflect.Value, args ...reflect.Value) bool { 91 | in := fn.Type().NumIn() 92 | res := fn.Call(args[0:in]) 93 | return res[0].Bool() 94 | } 95 | 96 | func callFn(fn reflect.Value, args ...reflect.Value) []reflect.Value { 97 | in := fn.Type().NumIn() 98 | // display(fn) 99 | res := fn.Call(args[0:in]) 100 | return res 101 | } 102 | -------------------------------------------------------------------------------- /underscore_test.go: -------------------------------------------------------------------------------- 1 | package un 2 | 3 | import ( 4 | "fmt" 5 | "path/filepath" 6 | "reflect" 7 | "runtime" 8 | "testing" 9 | ) 10 | 11 | var SLICE_STRING = []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"} 12 | 13 | var SLICE_INT = []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} 14 | 15 | var MAP_STRING_TO_INT = map[string]int{"a": 1, "b": 2, "c": 3, "d": 4, "e": 5, "f": 6, "g": 7, "h": 8, "i": 9, "j": 10, "k": 11, "l": 12, "m": 13, "n": 14, "o": 15, "p": 16, "q": 17, "r": 18, "s": 19, "t": 20, "u": 21, "v": 22, "w": 23, "x": 24, "y": 25, "z": 26} 16 | 17 | // Test functions From https://github.com/benbjohnson/testing 18 | // assert fails the test if the condition is false. 19 | func assert(tb testing.TB, condition bool, msg string, v ...interface{}) { 20 | if !condition { 21 | _, file, line, _ := runtime.Caller(1) 22 | fmt.Printf("\033[31m%s:%d: "+msg+"\033[39m\n\n", append([]interface{}{filepath.Base(file), line}, v...)...) 23 | tb.FailNow() 24 | } 25 | } 26 | 27 | // ok fails the test if an err is not nil. 28 | func ok(tb testing.TB, err error) { 29 | if err != nil { 30 | _, file, line, _ := runtime.Caller(1) 31 | fmt.Printf("\033[31m%s:%d: unexpected error: %s\033[39m\n\n", filepath.Base(file), line, err.Error()) 32 | tb.FailNow() 33 | } 34 | } 35 | 36 | // equals fails the test if exp is not equal to act. 37 | func equals(tb testing.TB, exp, act interface{}) { 38 | if !reflect.DeepEqual(exp, act) { 39 | _, file, line, _ := runtime.Caller(1) 40 | fmt.Printf("\033[31m%s:%d:\n\n\texp: %#v\n\n\tgot: %#v\033[39m\n\n", filepath.Base(file), line, exp, act) 41 | tb.FailNow() 42 | } 43 | } 44 | 45 | func display(i interface{}) { 46 | fmt.Printf("\033[32m%v\033[39m\n", i) 47 | } 48 | 49 | func inspect(i interface{}) { 50 | fmt.Printf("\033[32m%#v\033[39m\n", i) 51 | } 52 | 53 | func suite(i interface{}) { 54 | display(i) 55 | } 56 | 57 | func title(i interface{}) { 58 | s := fmt.Sprintf("- %v", i) 59 | display(s) 60 | } 61 | 62 | func TestValueize(t *testing.T) { 63 | i := reflect.ValueOf(42) 64 | s := "42" 65 | 66 | res := Valueize(i, s) 67 | equals(t, i, res[0]) 68 | equals(t, s, res[1].Interface()) 69 | } 70 | 71 | func TestToI(t *testing.T) { 72 | i := ToI(SLICE_STRING) 73 | 74 | if expected, received := len(SLICE_STRING), len(i); expected != received { 75 | t.Errorf("[ToI] Expected %v; Received %v", expected, received) 76 | } 77 | 78 | if expected, received := SLICE_STRING[0], i[0]; expected != received { 79 | t.Errorf("[ToI] Expected %v; Received %v", expected, received) 80 | } 81 | } 82 | 83 | func TestPredicateArity(t *testing.T) { 84 | oneArity := func(s int) bool { 85 | return s == 99 86 | } 87 | 88 | twoArity := func(s, i int) bool { 89 | return s == 99 && i == 99 90 | } 91 | 92 | v := reflect.ValueOf(99) 93 | res := callPredicate(reflect.ValueOf(oneArity), v) 94 | 95 | equals(t, true, res) 96 | 97 | res = callPredicate(reflect.ValueOf(oneArity), v, v) 98 | equals(t, true, res) 99 | 100 | res = callPredicate(reflect.ValueOf(twoArity), v, v) 101 | equals(t, true, res) 102 | 103 | values := []reflect.Value{v, v} 104 | res = callPredicate(reflect.ValueOf(twoArity), values...) 105 | equals(t, true, res) 106 | } 107 | --------------------------------------------------------------------------------