├── README.md ├── chunk.go ├── chunk_test.go ├── concat.go ├── concat_test.go ├── difference.go ├── difference_test.go ├── drop.go ├── drop_test.go ├── fill.go ├── fill_test.go ├── findIndex.go ├── findIndex_test.go ├── go.mod ├── go.sum ├── indexOf.go ├── indexOf_test.go ├── join.go ├── join_test.go ├── lastIndexOf.go ├── lastIndexOf_test.go ├── pointer.go ├── reverse.go ├── reverse_test.go ├── uniq.go └── uniq_test.go /README.md: -------------------------------------------------------------------------------- 1 | ## GO-Loadash 2 | 3 | * go implementation of the popular lodash library. 4 | 5 | 6 | Supportss Go version 1.18beta1 7 | 8 | 9 | // implementations 10 | 11 | - [x] Chunk 12 | - [ ] ~~Compact~~ 13 | - [x] Concat 14 | - [x] Difference 15 | - [x] DifferenceBy -> DifferenceByFunc 16 | - [x] DifferenceWith -> DifferenceByFunc 17 | - [x] Drop 18 | - [x] DropWhile -> DropWhileFunc 19 | - [x] DropRight 20 | - [x] DropRightWhile -> DropRightWhileFunc 21 | - [x] fill 22 | - [ ] findIndex -------------------------------------------------------------------------------- /chunk.go: -------------------------------------------------------------------------------- 1 | package go_lodash 2 | 3 | type ChunkType interface { 4 | int | int8 | int16 | int32 | int64 | float32 | float64 | string | map[string]interface{} 5 | } 6 | 7 | func Chunk[V ChunkType](array []V, size int) [][]V { 8 | res := make([][]V, 0) 9 | start := 0 10 | length := len(array) 11 | 12 | for start < length { 13 | end := start + size 14 | if end > length { 15 | end = length 16 | } 17 | res = append(res, array[start:end]) 18 | start = end 19 | } 20 | 21 | return res 22 | } 23 | -------------------------------------------------------------------------------- /chunk_test.go: -------------------------------------------------------------------------------- 1 | package go_lodash 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | var chunkTests = []struct { 10 | name string 11 | array []int 12 | size int 13 | want [][]int 14 | }{ 15 | {"even chunk", []int{1, 2, 3, 4}, 2, [][]int{{1, 2}, {3, 4}}}, 16 | {"odd chunk", []int{1, 2, 3, 4}, 3, [][]int{{1, 2, 3}, {4}}}, 17 | {"odd chunk", []int{1}, 3, [][]int{{1}}}, 18 | {"odd chunk", []int{}, 3, [][]int{}}, 19 | } 20 | 21 | func TestChunk(t *testing.T) { 22 | is := assert.New(t) 23 | for _, tt := range chunkTests { 24 | t.Run(tt.name, func(t *testing.T) { 25 | res := Chunk(tt.array, tt.size) 26 | is.Equal(tt.want, res) 27 | }) 28 | } 29 | } 30 | 31 | func TestChunkMap(t *testing.T) { 32 | is := assert.New(t) 33 | input := []map[string]interface{}{ 34 | {"a": "b"}, 35 | {"c": "d"}, 36 | {"e": "f"}, 37 | } 38 | 39 | expected := [][]map[string]interface{}{ 40 | { 41 | {"a": "b"}, 42 | {"c": "d"}, 43 | }, 44 | { 45 | {"e": "f"}, 46 | }, 47 | } 48 | 49 | res := Chunk(input, 2) 50 | is.Equal(expected, res) 51 | 52 | } 53 | -------------------------------------------------------------------------------- /concat.go: -------------------------------------------------------------------------------- 1 | package go_lodash 2 | 3 | type ConcatType interface { 4 | int | int8 | int16 | int32 | int64 | float32 | float64 | string | map[string]interface{} 5 | } 6 | 7 | // Concat Creates a new array concatenating array with any additional arrays and/or values. 8 | func Concat[V ConcatType](arrays ...[]V) []V { 9 | array := make([]V, 0) 10 | for _, arr := range arrays { 11 | array = append(array, arr...) 12 | } 13 | return array 14 | } 15 | -------------------------------------------------------------------------------- /concat_test.go: -------------------------------------------------------------------------------- 1 | package go_lodash 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | var concatTests = []struct { 10 | name string 11 | arrays [][]int 12 | want []int 13 | }{ 14 | {"test 1", [][]int{{1, 2, 3, 4}, {5}}, []int{1, 2, 3, 4, 5}}, 15 | {"test empty", [][]int{}, []int{}}, 16 | {"test nil", nil, []int{}}, 17 | } 18 | 19 | func TestConcat(t *testing.T) { 20 | is := assert.New(t) 21 | for _, tt := range concatTests { 22 | t.Run(tt.name, func(t *testing.T) { 23 | res := Concat(tt.arrays...) 24 | is.Equal(tt.want, res) 25 | }) 26 | } 27 | } 28 | 29 | func TestConcatMap(t *testing.T) { 30 | is := assert.New(t) 31 | input := [][]map[string]interface{}{ 32 | { 33 | {"a": "b"}, 34 | {"c": "d"}, 35 | {"e": "f"}, 36 | }, 37 | { 38 | {"g": "h"}, 39 | }, 40 | } 41 | 42 | expected := []map[string]interface{}{ 43 | {"a": "b"}, 44 | {"c": "d"}, 45 | {"e": "f"}, 46 | {"g": "h"}, 47 | } 48 | 49 | res := Concat(input...) 50 | is.Equal(expected, res) 51 | 52 | } 53 | -------------------------------------------------------------------------------- /difference.go: -------------------------------------------------------------------------------- 1 | package go_lodash 2 | 3 | type DifferenceType interface { 4 | int | int8 | int16 | int32 | int64 | float32 | float64 | string 5 | } 6 | 7 | func Difference[V DifferenceType](array []V, values []V) []V { 8 | result := make([]V, 0) 9 | lookup := map[V]struct{}{} 10 | 11 | // create a lookup 12 | for _, val := range values { 13 | lookup[val] = struct{}{} 14 | } 15 | 16 | for _, val := range array { 17 | if _, ok := lookup[val]; !ok { 18 | result = append(result, val) 19 | } 20 | } 21 | return result 22 | } 23 | 24 | type DifferenceFunc[V DifferenceType, X DifferenceType] func(value V) X 25 | 26 | func DifferenceBy[V DifferenceType, X DifferenceType](array []V, values []V, differenceByFunc DifferenceFunc[V, X]) []V { 27 | result := make([]V, 0) 28 | lookup := map[X]struct{}{} 29 | 30 | // create a lookup 31 | for _, val := range values { 32 | lookup[differenceByFunc(val)] = struct{}{} 33 | } 34 | 35 | for _, val := range array { 36 | if _, ok := lookup[differenceByFunc(val)]; !ok { 37 | result = append(result, val) 38 | } 39 | } 40 | 41 | return result 42 | } 43 | -------------------------------------------------------------------------------- /difference_test.go: -------------------------------------------------------------------------------- 1 | package go_lodash 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | var differenceTests = []struct { 10 | name string 11 | array []int 12 | values []int 13 | want []int 14 | }{ 15 | {"check difference", []int{1, 2}, []int{2, 3}, []int{1}}, 16 | {"same result", []int{1, 2, 3}, []int{4, 5, 6}, []int{1, 2, 3}}, 17 | {"emoty result", []int{1, 2, 3}, []int{1, 2, 3}, []int{}}, 18 | } 19 | 20 | func TestDifference(t *testing.T) { 21 | is := assert.New(t) 22 | for _, tt := range differenceTests { 23 | t.Run(tt.name, func(t *testing.T) { 24 | res := Difference(tt.array, tt.values) 25 | is.Equal(tt.want, res) 26 | }) 27 | } 28 | } 29 | 30 | var differenceTestsString = []struct { 31 | name string 32 | array []string 33 | values []string 34 | want []string 35 | }{ 36 | {"check difference", []string{"a", "b"}, []string{"c", "d"}, []string{"a"}}, 37 | {"check difference multiple chars", []string{"hello", "world"}, []string{"hello", "john"}, []string{"hello"}}, 38 | {"same result", []string{"a", "b", "c"}, []string{"d", "e", "f"}, []string{"a", "b", "c"}}, 39 | {"emoty result", []string{"a", "b", "c"}, []string{"a", "b", "c"}, []string{}}, 40 | } 41 | 42 | func TestDifference_String(t *testing.T) { 43 | is := assert.New(t) 44 | for _, tt := range differenceTests { 45 | t.Run(tt.name, func(t *testing.T) { 46 | res := Difference(tt.array, tt.values) 47 | is.Equal(tt.want, res) 48 | }) 49 | } 50 | } 51 | 52 | func TestDifferenceByFunc(t *testing.T) { 53 | is := assert.New(t) 54 | 55 | res := DifferenceBy([]float32{2.1, 1.2}, []float32{2.3, 3.5}, func(value float32) int { 56 | return int(value) 57 | }) 58 | is.Equal([]float32{1.2}, res) 59 | 60 | } 61 | -------------------------------------------------------------------------------- /drop.go: -------------------------------------------------------------------------------- 1 | package go_lodash 2 | 3 | type DropType interface { 4 | int | int8 | int16 | int32 | int64 | float32 | float64 | string | map[string]interface{} 5 | } 6 | 7 | func Drop[V DropType](array []V, n int) []V { 8 | if n > len(array) { 9 | return []V{} 10 | } 11 | return array[n:] 12 | } 13 | 14 | func DropRight[V DropType](array []V, n int) []V { 15 | if n > len(array) { 16 | return []V{} 17 | } 18 | return array[:len(array)-n] 19 | } 20 | 21 | type WhileFunc[V DropType] func(value V, index int, array []V) bool 22 | 23 | func DropWhileFunc[V DropType](array []V, whilefunc WhileFunc[V]) []V { 24 | for i, v := range array { 25 | if !whilefunc(v, i, array) { 26 | return array[i:] 27 | } 28 | } 29 | return []V{} 30 | } 31 | 32 | func DropWhileRightFunc[V DropType](array []V, whilefunc WhileFunc[V]) []V { 33 | for i := len(array) - 1; i >= 0; i-- { 34 | if !whilefunc(array[i], i, array) { 35 | return array[:i+1] 36 | } 37 | } 38 | return []V{} 39 | } 40 | -------------------------------------------------------------------------------- /drop_test.go: -------------------------------------------------------------------------------- 1 | package go_lodash 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | var dropTests = []struct { 11 | name string 12 | array []int 13 | n int 14 | want []int 15 | }{ 16 | {"drop", []int{1, 2}, 1, []int{2}}, 17 | {"drop 1", []int{1, 2, 3, 4, 5}, 2, []int{3, 4, 5}}, 18 | {"exceed drop", []int{1, 2, 3}, 5, []int{}}, 19 | } 20 | 21 | func TestDrop(t *testing.T) { 22 | is := assert.New(t) 23 | for _, tt := range dropTests { 24 | t.Run(tt.name, func(t *testing.T) { 25 | res := Drop(tt.array, tt.n) 26 | is.Equal(tt.want, res) 27 | }) 28 | } 29 | } 30 | 31 | var dropRightTests = []struct { 32 | name string 33 | array []int 34 | n int 35 | want []int 36 | }{ 37 | {"drop", []int{1, 2}, 1, []int{1}}, 38 | {"drop 1", []int{1, 2, 3, 4, 5}, 2, []int{1, 2, 3}}, 39 | {"exceed drop", []int{1, 2, 3}, 5, []int{}}, 40 | {"none drop", []int{1, 2}, 0, []int{1, 2}}, 41 | } 42 | 43 | func TestDropRight(t *testing.T) { 44 | is := assert.New(t) 45 | for _, tt := range dropRightTests { 46 | t.Run(tt.name, func(t *testing.T) { 47 | res := DropRight(tt.array, tt.n) 48 | is.Equal(tt.want, res) 49 | }) 50 | } 51 | } 52 | 53 | func TestDropWhileFunc(t *testing.T) { 54 | is := assert.New(t) 55 | res := DropWhileFunc([]int{1, 3, 4}, func(x int, i int, array []int) bool { 56 | if x <= 3 { 57 | return true 58 | } 59 | return false 60 | }) 61 | 62 | is.Equal([]int{4}, res) 63 | } 64 | 65 | func TestDropWhileObject(t *testing.T) { 66 | is := assert.New(t) 67 | input := []map[string]interface{}{ 68 | {"user": "barney", "active": false}, 69 | {"user": "fred", "active": false}, 70 | {"user": "pebbles", "active": true}, 71 | } 72 | res := DropWhileFunc(input, func(x map[string]interface{}, i int, array []map[string]interface{}) bool { 73 | val := x["active"].(bool) 74 | return !val 75 | }) 76 | is.Equal("pebbles", res[0]["user"].(string)) 77 | } 78 | 79 | func TestDropRightWhileFunc(t *testing.T) { 80 | is := assert.New(t) 81 | res := DropWhileRightFunc([]int{1, 3, 4}, func(x int, i int, array []int) bool { 82 | if x >= 3 { 83 | return true 84 | } 85 | return false 86 | }) 87 | 88 | is.Equal([]int{1}, res) 89 | } 90 | 91 | func TestDropRightWhileObject(t *testing.T) { 92 | is := assert.New(t) 93 | input := []map[string]interface{}{ 94 | {"user": "barney", "active": false}, 95 | {"user": "fred", "active": false}, 96 | {"user": "pebbles", "active": true}, 97 | } 98 | res := DropWhileRightFunc(input, func(x map[string]interface{}, i int, array []map[string]interface{}) bool { 99 | fmt.Println(x["user"]) 100 | val := x["active"].(bool) 101 | return val 102 | }) 103 | is.Equal("fred", res[1]["user"].(string)) 104 | } 105 | -------------------------------------------------------------------------------- /fill.go: -------------------------------------------------------------------------------- 1 | package go_lodash 2 | 3 | type FillType interface { 4 | int | int8 | int16 | int32 | int64 | float32 | float64 | string 5 | } 6 | 7 | type FillOptions struct { 8 | start *int 9 | end *int 10 | } 11 | 12 | // Fill elements of array with value from start up to, but not including, end. 13 | func Fill[V FillType](array []V, value V, options *FillOptions) ([]V, error) { 14 | start, end := 0, len(array) 15 | if options != nil { 16 | if options.start != nil { 17 | start = *options.start 18 | } 19 | 20 | if options.end != nil { 21 | end = *options.end 22 | } 23 | } 24 | 25 | if start < 0 { 26 | start = 0 27 | } 28 | if end > len(array) { 29 | end = len(array) 30 | } 31 | 32 | for i := start; i < end; i++ { 33 | array[i] = value 34 | } 35 | return array, nil 36 | } 37 | -------------------------------------------------------------------------------- /fill_test.go: -------------------------------------------------------------------------------- 1 | package go_lodash 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | var fillTests = []struct { 10 | name string 11 | array []int 12 | value int 13 | options *FillOptions 14 | want []int 15 | isError *bool 16 | wantError *string 17 | }{ 18 | {"t1", []int{1, 2, 3}, 10, &FillOptions{}, []int{10, 10, 10}, nil, nil}, 19 | {"t2", []int{1, 2, 3}, 10, &FillOptions{start: GetPointer(1)}, []int{1, 10, 10}, nil, nil}, 20 | } 21 | 22 | func TestFill(t *testing.T) { 23 | is := assert.New(t) 24 | for _, tt := range fillTests { 25 | t.Run(tt.name, func(t *testing.T) { 26 | res, err := Fill(tt.array, tt.value, tt.options) 27 | if tt.isError != nil && *tt.isError { 28 | is.Equal(tt.wantError, err.Error()) 29 | } else { 30 | is.Equal(tt.want, res) 31 | } 32 | }) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /findIndex.go: -------------------------------------------------------------------------------- 1 | package go_lodash 2 | 3 | type FindFunc[V any] func(value V, index int, array []V) bool 4 | 5 | // FindIndex This method is like _.find except that it returns the index of the first element predicate returns truth for instead of the element itself. 6 | // fromIndex default is 0 if nil 7 | func FindIndex[V any](array []V, findFunc FindFunc[V], fromIndex *int) int { 8 | if fromIndex == nil { 9 | fromIndex = GetPointer(0) 10 | } 11 | for index, val := range array { 12 | if findFunc(val, index, array) { 13 | return index 14 | } 15 | } 16 | return -1 17 | } 18 | -------------------------------------------------------------------------------- /findIndex_test.go: -------------------------------------------------------------------------------- 1 | package go_lodash 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestFindIndex(t *testing.T) { 10 | is := assert.New(t) 11 | res := FindIndex([]int{1, 2, 3, 4}, func(value int, index int, array []int) bool { 12 | if value == 3 { 13 | return true 14 | } 15 | return false 16 | }, 17 | nil, 18 | ) 19 | is.Equal(2, res) 20 | } 21 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/nityanandagohain/go_lodash 2 | 3 | go 1.18 4 | 5 | require github.com/stretchr/testify v1.7.0 6 | 7 | require ( 8 | github.com/davecgh/go-spew v1.1.0 // indirect 9 | github.com/pmezard/go-difflib v1.0.0 // indirect 10 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect 11 | ) 12 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= 2 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 4 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 5 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 6 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 7 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 8 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 9 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 10 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= 11 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 12 | -------------------------------------------------------------------------------- /indexOf.go: -------------------------------------------------------------------------------- 1 | package go_lodash 2 | 3 | type IndexOfType interface { 4 | int | int8 | int16 | int32 | int64 | float32 | float64 | string | bool 5 | } 6 | 7 | type IndexOfOptions struct { 8 | FromIndex *int 9 | } 10 | 11 | func IndexOf[V IndexOfType](array []V, value V, options *IndexOfOptions) int { 12 | fromIndex := 0 13 | if options != nil && options.FromIndex != nil { 14 | fromIndex = *options.FromIndex 15 | } 16 | 17 | if fromIndex < 0 { 18 | fromIndex = 0 19 | } 20 | 21 | for i := fromIndex; i < len(array); i++ { 22 | if array[i] == value { 23 | return i 24 | } 25 | } 26 | 27 | return -1 28 | } 29 | -------------------------------------------------------------------------------- /indexOf_test.go: -------------------------------------------------------------------------------- 1 | package go_lodash 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | var indexOfTests = []struct { 10 | name string 11 | array []int 12 | options *IndexOfOptions 13 | value int 14 | want int 15 | }{ 16 | {"value present", []int{1, 2, 3, 9}, nil, 2, 1}, 17 | {"using from", []int{1, 2, 3, 9}, &IndexOfOptions{FromIndex: GetPointer(1)}, 3, 2}, 18 | {"out of index 2", []int{1, 2, 3, 9}, nil, 0, -1}, 19 | } 20 | 21 | func TestIndexOf(t *testing.T) { 22 | is := assert.New(t) 23 | for _, tt := range indexOfTests { 24 | t.Run(tt.name, func(t *testing.T) { 25 | is.Equal(IndexOf(tt.array, tt.value, tt.options), tt.want) 26 | }) 27 | } 28 | } 29 | 30 | func TestIndexOf_string(t *testing.T) { 31 | is := assert.New(t) 32 | input := []string{"hello", "world", "how", "are", "you"} 33 | res := IndexOf(input, "are", nil) 34 | is.Equal(res, 3) 35 | } 36 | 37 | func TestIndexOf_float(t *testing.T) { 38 | is := assert.New(t) 39 | input := []float64{1.1, 2.3, 5.5} 40 | res := IndexOf(input, 2.3, nil) 41 | is.Equal(res, 1) 42 | } 43 | -------------------------------------------------------------------------------- /join.go: -------------------------------------------------------------------------------- 1 | package go_lodash 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type JoinType interface { 8 | int | int8 | int16 | int32 | int64 | float32 | float64 | string 9 | } 10 | 11 | func Join[V JoinType](array []V, separator string) string { 12 | result := "" 13 | for i, v := range array { 14 | if i > 0 { 15 | result += separator 16 | } 17 | result += fmt.Sprintf("%v", v) 18 | } 19 | 20 | return result 21 | } 22 | -------------------------------------------------------------------------------- /join_test.go: -------------------------------------------------------------------------------- 1 | package go_lodash 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | var joinTests = []struct { 10 | name string 11 | array []int 12 | seperator string 13 | want string 14 | }{ 15 | {"join", []int{1, 2, 3, 9}, "-", "1-2-3-9"}, 16 | } 17 | 18 | func TestJoin(t *testing.T) { 19 | is := assert.New(t) 20 | for _, tt := range joinTests { 21 | t.Run(tt.name, func(t *testing.T) { 22 | is.Equal(tt.want, Join(tt.array, tt.seperator)) 23 | }) 24 | } 25 | } 26 | 27 | var joinTest_string = []struct { 28 | name string 29 | array []string 30 | seperator string 31 | want string 32 | }{ 33 | {"join", []string{"abc", "def", "ghi", "jkl"}, "-", "abc-def-ghi-jkl"}, 34 | } 35 | 36 | func TestJoin_string(t *testing.T) { 37 | is := assert.New(t) 38 | for _, tt := range joinTest_string { 39 | t.Run(tt.name, func(t *testing.T) { 40 | is.Equal(tt.want, Join(tt.array, tt.seperator)) 41 | }) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /lastIndexOf.go: -------------------------------------------------------------------------------- 1 | package go_lodash 2 | 3 | type LastIndexOfType interface { 4 | int | int8 | int16 | int32 | int64 | float32 | float64 | string 5 | } 6 | 7 | type LastIndexOfOptions struct { 8 | FromIndex *int 9 | } 10 | 11 | func LastIndexOf[V LastIndexOfType](array []V, value V, options *LastIndexOfOptions) int { 12 | fromIndex := 0 13 | if options != nil && options.FromIndex != nil { 14 | fromIndex = *options.FromIndex 15 | } 16 | for i := len(array) - 1; i >= 0; i-- { 17 | if array[i] == value { 18 | return i - fromIndex 19 | } 20 | } 21 | return -1 22 | } 23 | -------------------------------------------------------------------------------- /lastIndexOf_test.go: -------------------------------------------------------------------------------- 1 | package go_lodash 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | var lastIndexOfTests = []struct { 10 | name string 11 | array []int 12 | value int 13 | options *LastIndexOfOptions 14 | want int 15 | }{ 16 | {"without options", []int{1, 2, 1, 2}, 2, nil, 3}, 17 | {"with options", []int{1, 2, 1, 2}, 2, &LastIndexOfOptions{FromIndex: GetPointer(2)}, 1}, 18 | } 19 | 20 | func TestLastIndexOf(t *testing.T) { 21 | is := assert.New(t) 22 | for _, tt := range lastIndexOfTests { 23 | t.Run(tt.name, func(t *testing.T) { 24 | is.Equal(tt.want, LastIndexOf(tt.array, tt.value, tt.options)) 25 | }) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /pointer.go: -------------------------------------------------------------------------------- 1 | package go_lodash 2 | 3 | type PointerType interface { 4 | int | int8 | int16 | int32 | int64 | float32 | float64 | string 5 | } 6 | 7 | func GetPointer[V JoinType](val V) *V { 8 | return &val 9 | } 10 | -------------------------------------------------------------------------------- /reverse.go: -------------------------------------------------------------------------------- 1 | package go_lodash 2 | 3 | type ReverseType interface { 4 | int | int8 | int16 | int32 | int64 | float32 | float64 | string 5 | } 6 | 7 | func Reverse[V ReverseType](array []V) []V { 8 | for i := len(array)/2 - 1; i >= 0; i-- { 9 | opp := len(array) - 1 - i 10 | array[i], array[opp] = array[opp], array[i] 11 | } 12 | 13 | return array 14 | } 15 | -------------------------------------------------------------------------------- /reverse_test.go: -------------------------------------------------------------------------------- 1 | package go_lodash 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | var ReverseTests = []struct { 10 | name string 11 | array []int 12 | want []int 13 | }{ 14 | {"test 1", []int{1, 2, 1, 2}, []int{2, 1, 2, 1}}, 15 | {"test 2", []int{1, 3, 5, 9}, []int{9, 5, 3, 1}}, 16 | {"test odd", []int{1, 3, 5}, []int{5, 3, 1}}, 17 | {"test empty", []int{}, []int{}}, 18 | } 19 | 20 | func TestReverse(t *testing.T) { 21 | is := assert.New(t) 22 | for _, tt := range ReverseTests { 23 | t.Run(tt.name, func(t *testing.T) { 24 | is.ElementsMatch(tt.want, Reverse(tt.array)) 25 | }) 26 | } 27 | } 28 | 29 | func TestReverse_string(t *testing.T) { 30 | is := assert.New(t) 31 | input := []string{"hello", "world"} 32 | res := Reverse(input) 33 | is.ElementsMatch([]string{"world", "hello"}, res) 34 | } 35 | -------------------------------------------------------------------------------- /uniq.go: -------------------------------------------------------------------------------- 1 | package go_lodash 2 | 3 | import ( 4 | "sort" 5 | ) 6 | 7 | type UniqType interface { 8 | int | int8 | int16 | int32 | int64 | float32 | float64 | string 9 | } 10 | 11 | func Uniq[V UniqType](array []V) []V { 12 | if len(array) == 0 { 13 | return array 14 | } 15 | 16 | out := make([]V, len(array)) 17 | copy(out, array) 18 | 19 | sort.Slice(array, func(i, j int) bool { 20 | return array[i] < array[j] 21 | }) 22 | 23 | result := out[:0] 24 | for i := 0; i < len(array); i++ { 25 | if len(result) == 0 || result[len(result)-1] != array[i] { 26 | result = append(result, array[i]) 27 | } 28 | } 29 | 30 | return result 31 | } 32 | 33 | type UniqByFunc[V UniqType, X UniqType] func(value V, index int, array []V) X 34 | 35 | func UniqBy[V UniqType, X UniqType](array []V, uniqFunc UniqByFunc[V, X]) []V { 36 | lookup := map[X]struct{}{} 37 | result := make([]V, 0, len(array)) 38 | 39 | for i := 0; i < len(array); i++ { 40 | val := uniqFunc(array[i], i, array) 41 | if _, ok := lookup[val]; !ok { 42 | lookup[val] = struct{}{} 43 | result = append(result, array[i]) 44 | } 45 | } 46 | return result 47 | } 48 | -------------------------------------------------------------------------------- /uniq_test.go: -------------------------------------------------------------------------------- 1 | package go_lodash 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | var UniqTests = []struct { 11 | name string 12 | array []int 13 | want []int 14 | }{ 15 | {"test 1", []int{1, 2, 1, 2}, []int{1, 2}}, 16 | {"test 2", []int{1, 3, 5, 9}, []int{1, 3, 5, 9}}, 17 | {"test empty", []int{}, []int{}}, 18 | } 19 | 20 | func TestUniq(t *testing.T) { 21 | is := assert.New(t) 22 | for _, tt := range UniqTests { 23 | t.Run(tt.name, func(t *testing.T) { 24 | is.ElementsMatch(tt.want, Uniq(tt.array)) 25 | }) 26 | } 27 | } 28 | 29 | func TestUniq_string(t *testing.T) { 30 | is := assert.New(t) 31 | input := []string{"hello", "world", "world"} 32 | res := Uniq(input) 33 | is.ElementsMatch([]string{"hello", "world"}, res) 34 | } 35 | 36 | func TestUniqBy(t *testing.T) { 37 | is := assert.New(t) 38 | input := []float32{2.1, 1.2, 2.3} 39 | res := UniqBy(input, func(value float32, index int, array []float32) int { 40 | fmt.Println(int(value)) 41 | return int(value) 42 | }) 43 | is.ElementsMatch([]float32{2.1, 1.2}, res) 44 | } 45 | 46 | func BenchmarkUniq(b *testing.B) { 47 | for i := 0; i < b.N; i++ { 48 | for _, tt := range UniqTests { 49 | Uniq(tt.array) 50 | } 51 | } 52 | } 53 | 54 | func BenchmarkUniq1(b *testing.B) { 55 | for i := 0; i < b.N; i++ { 56 | for _, tt := range UniqTests { 57 | Uniq1(tt.array) 58 | } 59 | } 60 | } 61 | 62 | func BenchmarkUniqBy(b *testing.B) { 63 | for i := 0; i < b.N; i++ { 64 | for _, tt := range UniqTests { 65 | UniqBy(tt.array, func(value int, index int, array []int) int { 66 | return value 67 | }) 68 | } 69 | } 70 | } 71 | 72 | func BenchmarkUniqBy1(b *testing.B) { 73 | for i := 0; i < b.N; i++ { 74 | for _, tt := range UniqTests { 75 | UniqBy1(tt.array, func(value int, index int, array []int) int { 76 | return value 77 | }) 78 | } 79 | } 80 | } 81 | 82 | func Uniq1[V UniqType](array []V) []V { 83 | lookup := map[V]bool{} 84 | for i := 0; i < len(array); i++ { 85 | if _, ok := lookup[array[i]]; !ok { 86 | lookup[array[i]] = true 87 | } 88 | } 89 | 90 | result := make([]V, 0, len(lookup)) 91 | for key := range lookup { 92 | result = append(result, key) 93 | } 94 | 95 | return result 96 | } 97 | 98 | func UniqBy1[V UniqType, X UniqType](array []V, uniqFunc UniqByFunc[V, X]) []V { 99 | lookup := map[X]bool{} 100 | result := make([]V, 0, len(lookup)) 101 | for i := 0; i < len(array); i++ { 102 | val := uniqFunc(array[i], i, array) 103 | if _, ok := lookup[val]; !ok { 104 | lookup[val] = true 105 | result = append(result, array[i]) 106 | } 107 | } 108 | return result 109 | } 110 | --------------------------------------------------------------------------------