├── .chglog ├── CHANGELOG.tpl.md └── config.yml ├── .github └── workflows │ └── go.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── add_test.go ├── bool.go ├── bool_test.go ├── clear_test.go ├── contains_test.go ├── deduplicate_test.go ├── float32.go ├── float32_test.go ├── float64.go ├── float64_test.go ├── go.mod ├── int.go ├── int16.go ├── int16_test.go ├── int32.go ├── int32_test.go ├── int64.go ├── int64_test.go ├── int8.go ├── int8_test.go ├── int_test.go ├── interface.go ├── interface_test.go ├── join_test.go ├── length_test.go ├── logo.png ├── scripts ├── generate.go └── slicer.template ├── string.go ├── string_test.go ├── uint.go ├── uint16.go ├── uint16_test.go ├── uint32.go ├── uint32_test.go ├── uint64.go ├── uint64_test.go ├── uint8.go ├── uint8_test.go └── uint_test.go /.chglog/CHANGELOG.tpl.md: -------------------------------------------------------------------------------- 1 | {{ if .Versions -}} 2 | 3 | ## [Unreleased] 4 | 5 | {{ if .Unreleased.CommitGroups -}} 6 | {{ range .Unreleased.CommitGroups -}} 7 | ### {{ .Title }} 8 | {{ range .Commits -}} 9 | - {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }} 10 | {{ end }} 11 | {{ end -}} 12 | {{ end -}} 13 | {{ end -}} 14 | 15 | {{ range .Versions }} 16 | 17 | ## {{ if .Tag.Previous }}[{{ .Tag.Name }}]{{ else }}{{ .Tag.Name }}{{ end }} - {{ datetime "2006-01-02" .Tag.Date }} 18 | {{ range .CommitGroups -}} 19 | ### {{ .Title }} 20 | {{ range .Commits -}} 21 | - {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }} 22 | {{ end }} 23 | {{ end -}} 24 | 25 | {{- if .NoteGroups -}} 26 | {{ range .NoteGroups -}} 27 | ### {{ .Title }} 28 | {{ range .Notes }} 29 | {{ .Body }} 30 | {{ end }} 31 | {{ end -}} 32 | {{ end -}} 33 | {{ end -}} 34 | 35 | {{- if .Versions }} 36 | [Unreleased]: {{ .Info.RepositoryURL }}/compare/{{ $latest := index .Versions 0 }}{{ $latest.Tag.Name }}...HEAD 37 | {{ range .Versions -}} 38 | {{ if .Tag.Previous -}} 39 | [{{ .Tag.Name }}]: {{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }} 40 | {{ end -}} 41 | {{ end -}} 42 | {{ end -}} -------------------------------------------------------------------------------- /.chglog/config.yml: -------------------------------------------------------------------------------- 1 | style: github 2 | template: CHANGELOG.tpl.md 3 | info: 4 | title: CHANGELOG 5 | repository_url: https://github.com/leaanthony/slicer 6 | options: 7 | commits: 8 | # filters: 9 | # Type: 10 | # - feat 11 | # - fix 12 | # - perf 13 | # - refactor 14 | commit_groups: 15 | # title_maps: 16 | # feat: Features 17 | # fix: Bug Fixes 18 | # perf: Performance Improvements 19 | # refactor: Code Refactoring 20 | header: 21 | pattern: "^(\\w*)\\:\\s(.*)$" 22 | pattern_maps: 23 | - Type 24 | - Subject 25 | notes: 26 | keywords: 27 | - BREAKING CHANGE -------------------------------------------------------------------------------- /.github/workflows/go.yml: -------------------------------------------------------------------------------- 1 | name: Go 2 | on: [push] 3 | jobs: 4 | 5 | build: 6 | name: Build 7 | runs-on: ubuntu-latest 8 | steps: 9 | 10 | - name: Set up Go 1.13 11 | uses: actions/setup-go@v1 12 | with: 13 | go-version: 1.13 14 | id: go 15 | 16 | - name: Check out code into the Go module directory 17 | uses: actions/checkout@v1 18 | 19 | - name: Get dependencies 20 | run: | 21 | go get -v -t -d ./... 22 | if [ -f Gopkg.toml ]; then 23 | curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh 24 | dep ensure 25 | fi 26 | 27 | - name: Build 28 | run: go build -v . 29 | 30 | - name: Test 31 | run: go test -race -coverprofile=coverage.txt -covermode=atomic 32 | 33 | - name: CodeCov 34 | uses: codecov/codecov-action@v1 35 | with: 36 | token: ${{ secrets.CODECOV_TOKEN }} #required 37 | file: ./coverage.txt 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, build with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | coverage.txt 14 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | ## [Unreleased] 3 | 4 | 5 | 6 | ## [v1.3.1] - 2019-03-03 7 | ### Fix 8 | - Fix Float tests 9 | 10 | 11 | 12 | ## [v1.3.0] - 2019-03-03 13 | ### Feat 14 | - Add optional slice as part of construction 15 | 16 | 17 | 18 | ## [v1.2.0] - 2019-02-26 19 | ### Chore 20 | - add changelog 21 | 22 | ### Feat 23 | - Add Slicer.Each() 24 | 25 | 26 | 27 | ## [v1.1.0] - 2019-02-26 28 | ### Feat 29 | - Added Filter 30 | 31 | 32 | 33 | ## v1.0.0 - 2019-01-13 34 | 35 | [Unreleased]: https://github.com/leaanthony/slicer/compare/v1.3.1...HEAD 36 | [v1.3.1]: https://github.com/leaanthony/slicer/compare/v1.3.0...v1.3.1 37 | [v1.3.0]: https://github.com/leaanthony/slicer/compare/v1.2.0...v1.3.0 38 | [v1.2.0]: https://github.com/leaanthony/slicer/compare/v1.1.0...v1.2.0 39 | [v1.1.0]: https://github.com/leaanthony/slicer/compare/v1.0.0...v1.1.0 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Lea Anthony 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | Utility class for handling slices. 5 |
6 | 7 | 8 | [![Go Report Card](https://goreportcard.com/badge/github.com/leaanthony/slicer)](https://goreportcard.com/report/github.com/leaanthony/slicer) [![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](http://godoc.org/github.com/leaanthony/slicer) [![CodeFactor](https://www.codefactor.io/repository/github/leaanthony/slicer/badge)](https://www.codefactor.io/repository/github/leaanthony/slicer) [![codecov](https://codecov.io/gh/leaanthony/slicer/branch/master/graph/badge.svg)](https://codecov.io/gh/leaanthony/slicer) [![Mentioned in Awesome Go](https://awesome.re/mentioned-badge.svg)](https://github.com/avelino/awesome-go) 9 | 10 | 11 | 12 | 13 | 14 | ## Install 15 | 16 | `go get -u github.com/leaanthony/slicer` 17 | 18 | ## Quick Start 19 | 20 | ``` 21 | import "github.com/leaanthony/slicer" 22 | 23 | func test() { 24 | s := slicer.String() 25 | s.Add("one") 26 | s.Add("two") 27 | s.AddSlice([]string{"three","four"}) 28 | fmt.Printf("My slice = %+v\n", s.AsSlice()) 29 | 30 | t := slicer.String() 31 | t.Add("zero") 32 | t.AddSlicer(s) 33 | fmt.Printf("My slice = %+v\n", t.AsSlice()) 34 | } 35 | ``` 36 | 37 | ## Available slicers 38 | 39 | - Int 40 | - Int8 41 | - Int16 42 | - Int32 43 | - Int64 44 | - UInt 45 | - UInt8 46 | - UInt16 47 | - UInt32 48 | - UInt64 49 | - Float32 50 | - Float64 51 | - String 52 | - Bool 53 | - Interface 54 | 55 | ## API 56 | 57 | ### Construction 58 | 59 | Create new Slicers by calling one of the following functions: 60 | - Int() 61 | - Int8() 62 | - Int16() 63 | - Int32() 64 | - Int64() 65 | - Float32() 66 | - Float64() 67 | - String() 68 | - Bool() 69 | - Interface() 70 | 71 | ``` 72 | s := slicer.String() 73 | ``` 74 | 75 | If you wish to convert an existing slice to a Slicer, you may pass it in during creation: 76 | 77 | ``` 78 | values := []string{"one", "two", "three"} 79 | s := slicer.String(values) 80 | ``` 81 | 82 | ### Add 83 | 84 | Adds a value to the slice. 85 | 86 | ``` 87 | values := []string{"one", "two", "three"} 88 | s := slicer.String(values) 89 | s.Add("four") 90 | ``` 91 | 92 | ### AddUnique 93 | 94 | Adds a value to the slice if it doesn't already contain it. 95 | 96 | ``` 97 | values := []string{"one", "two", "three", "one", "two", "three"} 98 | s := slicer.String(values) 99 | result := s.Join(",") 100 | // result is "one,two,three" 101 | ``` 102 | ### AddSlice 103 | 104 | Adds an existing slice of values to a slicer 105 | 106 | ``` 107 | s := slicer.String([]string{"one"}) 108 | s.AddSlice([]string{"two"}) 109 | ``` 110 | 111 | ### AsSlice 112 | 113 | Returns a regular slice from the slicer. 114 | 115 | ``` 116 | s := slicer.String([]string{"one"}) 117 | for _, value := range s.AsSlice() { 118 | ... 119 | } 120 | ``` 121 | 122 | ### AddSlicer 123 | 124 | Adds an existing slicer of values to another slicer 125 | 126 | ``` 127 | a := slicer.String([]string{"one"}) 128 | b := slicer.String([]string{"two"}) 129 | a.AddSlicer(b) 130 | ``` 131 | 132 | ### Filter 133 | 134 | Filter the values of a slicer based on the result of calling the given function with each value of the slice. If it returns true, the value is added to the result. 135 | 136 | ``` 137 | a := slicer.Int([]int{1,5,7,9,6,3,1,9,1}) 138 | result := a.Filter(func(v int) bool { 139 | return v > 5 140 | }) 141 | // result is []int{7,9,9} 142 | 143 | ``` 144 | 145 | ### Each 146 | 147 | Each iterates over all the values of a slicer, passing them in as paramter to a function 148 | 149 | ``` 150 | a := slicer.Int([]int{1,5,7,9,6,3,1,9,1}) 151 | result := 0 152 | a.Each(func(v int) { 153 | result += v 154 | }) 155 | // result is 42 156 | ``` 157 | 158 | ### Contains 159 | 160 | Contains returns true if the slicer contains the given value 161 | 162 | ``` 163 | a := slicer.Int([]int{1,5,7,9,6,3,1,9,1}) 164 | result := a.Contains(9) 165 | // result is True 166 | ``` 167 | 168 | ### Join 169 | 170 | Returns a string with the slicer elements separated by the given separator 171 | 172 | ``` 173 | a := slicer.String([]string{"one", "two", "three"}) 174 | result := a.Join(",") 175 | // result is "one,two,three" 176 | ``` 177 | ### Length 178 | 179 | Returns the length of the slice 180 | 181 | ``` 182 | a := slicer.String([]string{"one", "two", "three"}) 183 | result := a.Length() 184 | // result is 3 185 | ``` 186 | 187 | ### Clear 188 | 189 | Clears all elements from the current slice 190 | 191 | ``` 192 | a := slicer.String([]string{"one", "two", "three"}) 193 | a.Clear() 194 | // a.Length() == 0 195 | ``` 196 | 197 | ### Sort 198 | 199 | Sorts the elements of a slice 200 | Not supported by: InterfaceSlicer, BoolSlicer 201 | 202 | ``` 203 | a := slicer.Int([]int{5,3,4,1,2}) 204 | a.Sort() 205 | // a is []int{1,2,3,4,5} 206 | ``` 207 | 208 | ### Deduplicate 209 | 210 | Deduplicate removes all duplicates within a slice. 211 | 212 | ``` 213 | a := slicer.Int([]int{5,3,5,1,3}) 214 | a.Deduplicate() 215 | // a is []int{5,3,1} 216 | ``` 217 | -------------------------------------------------------------------------------- /add_test.go: -------------------------------------------------------------------------------- 1 | package slicer 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | ) 7 | 8 | func TestStringAdd(t *testing.T) { 9 | 10 | s := String() 11 | s.Add("one") 12 | s.Add("two") 13 | 14 | expected := "one two" 15 | actual := strings.Join(s.AsSlice(), " ") 16 | if expected != actual { 17 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 18 | } 19 | 20 | // Add more than one value 21 | s.Clear() 22 | s.Add("one", "two") 23 | actual = strings.Join(s.AsSlice(), " ") 24 | if expected != actual { 25 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 26 | } 27 | } 28 | 29 | func TestStringAddUnique(t *testing.T) { 30 | 31 | s := String() 32 | s.AddUnique("one") 33 | s.AddUnique("one") 34 | s.AddUnique("two") 35 | s.AddUnique("two") 36 | 37 | expected := "one two" 38 | actual := strings.Join(s.AsSlice(), " ") 39 | if expected != actual { 40 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 41 | } 42 | 43 | // AddUnique more than one value 44 | s.Clear() 45 | s.AddUnique("one", "two", "two") 46 | actual = strings.Join(s.AsSlice(), " ") 47 | if expected != actual { 48 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 49 | } 50 | } 51 | 52 | func TestStringAddSlice(t *testing.T) { 53 | 54 | s := String() 55 | s.Add("one") 56 | s.Add("two") 57 | extras := []string{"three", "four"} 58 | s.AddSlice(extras) 59 | 60 | expected := "one two three four" 61 | actual := strings.Join(s.AsSlice(), " ") 62 | if expected != actual { 63 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 64 | } 65 | } 66 | 67 | func TestStringAddSlicer(t *testing.T) { 68 | 69 | s := String() 70 | s.Add("one") 71 | s.Add("two") 72 | 73 | p := String() 74 | p.Add("three") 75 | p.Add("four") 76 | 77 | s.AddSlicer(p) 78 | 79 | expected := "one two three four" 80 | actual := strings.Join(s.AsSlice(), " ") 81 | if expected != actual { 82 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /bool.go: -------------------------------------------------------------------------------- 1 | // Package slicer contains utility classes for handling slices 2 | package slicer 3 | 4 | // Imports 5 | import "fmt" 6 | import "strings" 7 | 8 | // BoolSlicer handles slices of bool 9 | type BoolSlicer struct { 10 | slice []bool 11 | } 12 | 13 | // Bool creates a new BoolSlicer 14 | func Bool(slice ...[]bool) *BoolSlicer { 15 | if len(slice) > 0 { 16 | return &BoolSlicer{slice: slice[0]} 17 | } 18 | return &BoolSlicer{} 19 | } 20 | 21 | // Add a bool value to the slicer 22 | func (s *BoolSlicer) Add(value bool, additional ...bool) { 23 | s.slice = append(s.slice, value) 24 | s.slice = append(s.slice, additional...) 25 | } 26 | 27 | // AddUnique adds a bool value to the slicer if it does not already exist 28 | func (s *BoolSlicer) AddUnique(value bool, additional ...bool) { 29 | 30 | if !s.Contains(value) { 31 | s.slice = append(s.slice, value) 32 | } 33 | 34 | // Add additional values 35 | for _, value := range additional { 36 | if !s.Contains(value) { 37 | s.slice = append(s.slice, value) 38 | } 39 | } 40 | } 41 | 42 | // AddSlice adds a bool slice to the slicer 43 | func (s *BoolSlicer) AddSlice(value []bool) { 44 | s.slice = append(s.slice, value...) 45 | } 46 | 47 | // AsSlice returns the slice 48 | func (s *BoolSlicer) AsSlice() []bool { 49 | return s.slice 50 | } 51 | 52 | // AddSlicer appends a BoolSlicer to the slicer 53 | func (s *BoolSlicer) AddSlicer(value *BoolSlicer) { 54 | s.slice = append(s.slice, value.AsSlice()...) 55 | } 56 | 57 | // Filter the slice based on the given function 58 | func (s *BoolSlicer) Filter(fn func(bool) bool) *BoolSlicer { 59 | result := &BoolSlicer{} 60 | for _, elem := range s.slice { 61 | if fn(elem) { 62 | result.Add(elem) 63 | } 64 | } 65 | return result 66 | } 67 | 68 | // Each runs a function on every element of the slice 69 | func (s *BoolSlicer) Each(fn func(bool)) { 70 | for _, elem := range s.slice { 71 | fn(elem) 72 | } 73 | } 74 | 75 | // Contains indicates if the given value is in the slice 76 | func (s *BoolSlicer) Contains(matcher bool) bool { 77 | result := false 78 | for _, elem := range s.slice { 79 | if elem == matcher { 80 | result = true 81 | } 82 | } 83 | return result 84 | } 85 | 86 | // Length returns the number of elements in the slice 87 | func (s *BoolSlicer) Length() int { 88 | return len(s.slice) 89 | } 90 | 91 | // Clear all elements in the slice 92 | func (s *BoolSlicer) Clear() { 93 | s.slice = []bool{} 94 | } 95 | 96 | // Deduplicate removes duplicate values from the slice 97 | func (s *BoolSlicer) Deduplicate() { 98 | 99 | result := &BoolSlicer{} 100 | 101 | for _, elem := range s.slice { 102 | if !result.Contains(elem) { 103 | result.Add(elem) 104 | } 105 | } 106 | 107 | s.slice = result.AsSlice() 108 | } 109 | 110 | // Join returns a string with the slicer elements separated by the given separator 111 | func (s *BoolSlicer) Join(separator string) string { 112 | var builder strings.Builder 113 | 114 | // Shortcut no elements 115 | if len(s.slice) == 0 { 116 | return "" 117 | } 118 | 119 | // Iterate over length - 1 120 | index := 0 121 | for index = 0; index < len(s.slice)-1; index++ { 122 | builder.WriteString(fmt.Sprintf("%v%s", s.slice[index], separator)) 123 | } 124 | builder.WriteString(fmt.Sprintf("%v", s.slice[index])) 125 | result := builder.String() 126 | return result 127 | } 128 | -------------------------------------------------------------------------------- /bool_test.go: -------------------------------------------------------------------------------- 1 | package slicer 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "testing" 7 | ) 8 | 9 | func TestBoolAddUnique(t *testing.T) { 10 | 11 | s := Bool() 12 | s.AddUnique(true) 13 | s.AddUnique(true) 14 | 15 | expected := "[true]" 16 | actual, _ := json.Marshal(s.AsSlice()) 17 | if expected != string(actual) { 18 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 19 | } 20 | 21 | s.Clear() 22 | s.AddUnique(true, false) 23 | 24 | expected = "[true,false]" 25 | actual, _ = json.Marshal(s.AsSlice()) 26 | if expected != string(actual) { 27 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 28 | } 29 | } 30 | func TestBoolAdd(t *testing.T) { 31 | 32 | s := Bool() 33 | s.Add(true) 34 | s.Add(false) 35 | 36 | expected := "[true,false]" 37 | actual, _ := json.Marshal(s.AsSlice()) 38 | if expected != string(actual) { 39 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 40 | } 41 | 42 | s.Clear() 43 | s.Add(true, false) 44 | 45 | expected = "[true,false]" 46 | actual, _ = json.Marshal(s.AsSlice()) 47 | if expected != string(actual) { 48 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 49 | } 50 | } 51 | 52 | func TestBoolAddSlice(t *testing.T) { 53 | 54 | s := Bool() 55 | s.Add(true) 56 | s.Add(false) 57 | 58 | extras := []bool{true, false} 59 | 60 | s.AddSlice(extras) 61 | 62 | expected := "[true,false,true,false]" 63 | actual, _ := json.Marshal(s.AsSlice()) 64 | if expected != string(actual) { 65 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 66 | } 67 | } 68 | 69 | func TestBoolAddSlicer(t *testing.T) { 70 | 71 | s := Bool() 72 | s.Add(true) 73 | s.Add(false) 74 | 75 | p := Bool() 76 | p.Add(true) 77 | p.Add(false) 78 | 79 | s.AddSlicer(p) 80 | 81 | expected := "[true,false,true,false]" 82 | actual, _ := json.Marshal(s.AsSlice()) 83 | if expected != string(actual) { 84 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 85 | } 86 | } 87 | 88 | func TestBoolFilter(t *testing.T) { 89 | 90 | s := Bool() 91 | s.Add(true) 92 | s.Add(false) 93 | s.Add(true) 94 | s.Add(true) 95 | s.Add(false) 96 | 97 | result := s.Filter(func(i bool) bool { 98 | return i == true 99 | }) 100 | 101 | expected := 3 102 | actual := len(result.AsSlice()) 103 | if actual != expected { 104 | t.Errorf("Expected '%d', but got '%d'", expected, actual) 105 | } 106 | } 107 | 108 | func TestBoolEach(t *testing.T) { 109 | 110 | s := Bool() 111 | s.Add(true) 112 | s.Add(false) 113 | s.Add(true) 114 | s.Add(true) 115 | s.Add(false) 116 | 117 | result := "" 118 | s.Each(func(i bool) { 119 | result += fmt.Sprintf("%t", i) 120 | }) 121 | 122 | var expected = "truefalsetruetruefalse" 123 | if expected != result { 124 | t.Errorf("Expected '%s', but got '%s'", expected, result) 125 | } 126 | } 127 | 128 | // TestOptionalBoolSlice tests 129 | func TestOptionalBoolSlice(t *testing.T) { 130 | data := []bool{true, false} 131 | s := Bool(data) 132 | 133 | var result string 134 | s.Each(func(elem bool) { 135 | result += fmt.Sprintf("%t", elem) 136 | }) 137 | var expected = "truefalse" 138 | if expected != result { 139 | t.Errorf("Expected '%s', but got '%s'", expected, result) 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /clear_test.go: -------------------------------------------------------------------------------- 1 | package slicer 2 | 3 | import "testing" 4 | 5 | func TestStringClear(t *testing.T) { 6 | data := []string{"cat", "bat", "dog", "arachnid"} 7 | s := String(data) 8 | 9 | expected := 4 10 | result := s.Length() 11 | if result != expected { 12 | t.Errorf("Expected %d, but got %d", expected, result) 13 | } 14 | s.Clear() 15 | if s.Length() != 0 { 16 | t.Errorf("Expected %d, but got %d", expected, result) 17 | } 18 | } 19 | 20 | func TestInterfaceClear(t *testing.T) { 21 | 22 | s := Interface() 23 | var a interface{} = 1 24 | var b interface{} = "hello" 25 | s.Add(a) 26 | s.Add(b) 27 | 28 | expected := 2 29 | result := s.Length() 30 | if result != expected { 31 | t.Errorf("Expected %d, but got %d", expected, result) 32 | } 33 | s.Clear() 34 | if s.Length() != 0 { 35 | t.Errorf("Expected %d, but got %d", expected, result) 36 | } 37 | } 38 | func TestInt32Clear(t *testing.T) { 39 | 40 | data := []int32{1, 2, 3} 41 | s := Int32(data) 42 | 43 | expected := 3 44 | result := s.Length() 45 | if result != expected { 46 | t.Errorf("Expected %d, but got %d", expected, result) 47 | } 48 | s.Clear() 49 | if s.Length() != 0 { 50 | t.Errorf("Expected %d, but got %d", expected, result) 51 | } 52 | } 53 | 54 | func TestInt16Clear(t *testing.T) { 55 | 56 | data := []int16{1, 2, 3} 57 | s := Int16(data) 58 | 59 | expected := 3 60 | result := s.Length() 61 | if result != expected { 62 | t.Errorf("Expected %d, but got %d", expected, result) 63 | } 64 | s.Clear() 65 | if s.Length() != 0 { 66 | t.Errorf("Expected %d, but got %d", expected, result) 67 | } 68 | } 69 | 70 | func TestInt8Clear(t *testing.T) { 71 | 72 | data := []int8{1, 2, 3} 73 | s := Int8(data) 74 | 75 | expected := 3 76 | result := s.Length() 77 | if result != expected { 78 | t.Errorf("Expected %d, but got %d", expected, result) 79 | } 80 | s.Clear() 81 | if s.Length() != 0 { 82 | t.Errorf("Expected %d, but got %d", expected, result) 83 | } 84 | } 85 | 86 | func TestIntClear(t *testing.T) { 87 | 88 | data := []int{1, 2, 3} 89 | s := Int(data) 90 | 91 | expected := 3 92 | result := s.Length() 93 | if result != expected { 94 | t.Errorf("Expected %d, but got %d", expected, result) 95 | } 96 | s.Clear() 97 | if s.Length() != 0 { 98 | t.Errorf("Expected %d, but got %d", expected, result) 99 | } 100 | } 101 | 102 | func TestBoolClear(t *testing.T) { 103 | 104 | data := []bool{true} 105 | s := Bool(data) 106 | 107 | expected := 1 108 | result := s.Length() 109 | if result != expected { 110 | t.Errorf("Expected %d, but got %d", expected, result) 111 | } 112 | s.Clear() 113 | if s.Length() != 0 { 114 | t.Errorf("Expected %d, but got %d", expected, result) 115 | } 116 | } 117 | 118 | func TestFloat64Clear(t *testing.T) { 119 | 120 | data := []float64{1.4, 2.1, 3} 121 | s := Float64(data) 122 | 123 | expected := 3 124 | result := s.Length() 125 | if result != expected { 126 | t.Errorf("Expected %d, but got %d", expected, result) 127 | } 128 | s.Clear() 129 | if s.Length() != 0 { 130 | t.Errorf("Expected %d, but got %d", expected, result) 131 | } 132 | } 133 | func TestFloat32Clear(t *testing.T) { 134 | 135 | data := []float32{1.4, 2.1, 3} 136 | s := Float32(data) 137 | 138 | expected := 3 139 | result := s.Length() 140 | if result != expected { 141 | t.Errorf("Expected %d, but got %d", expected, result) 142 | } 143 | s.Clear() 144 | if s.Length() != 0 { 145 | t.Errorf("Expected %d, but got %d", expected, result) 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /contains_test.go: -------------------------------------------------------------------------------- 1 | package slicer 2 | 3 | import "testing" 4 | 5 | func TestStringContains(t *testing.T) { 6 | data := []string{"cat", "bat", "dog", "arachnid"} 7 | s := String(data) 8 | 9 | // Positive test 10 | expected := true 11 | result := s.Contains("cat") 12 | if result != expected { 13 | t.Errorf("Expected '%t', but got '%t'", expected, result) 14 | } 15 | 16 | // Negative test 17 | expected = false 18 | result = s.Contains("horse") 19 | if result != expected { 20 | t.Errorf("Expected '%t', but got '%t'", expected, result) 21 | } 22 | } 23 | 24 | func TestInterfaceContains(t *testing.T) { 25 | 26 | s := Interface() 27 | var a interface{} = 1 28 | var b interface{} = "hello" 29 | s.Add(a) 30 | s.Add(b) 31 | 32 | // Positive test 33 | expected := true 34 | result := s.Contains(a) 35 | if result != expected { 36 | t.Errorf("Expected '%t', but got '%t'", expected, result) 37 | } 38 | 39 | // Negative test 40 | expected = false 41 | var dummy interface{} = 5 42 | result = s.Contains(dummy) 43 | if result != expected { 44 | t.Errorf("Expected '%t', but got '%t'", expected, result) 45 | } 46 | } 47 | 48 | func TestInt64Contains(t *testing.T) { 49 | 50 | data := []int64{1, 2, 3} 51 | s := Int64(data) 52 | 53 | // Positive test 54 | expected := true 55 | result := s.Contains(2) 56 | if result != expected { 57 | t.Errorf("Expected '%t', but got '%t'", expected, result) 58 | } 59 | 60 | // Negative test 61 | expected = false 62 | var badValue int64 = 9 63 | result = s.Contains(badValue) 64 | if result != expected { 65 | t.Errorf("Expected '%t', but got '%t'", expected, result) 66 | } 67 | } 68 | func TestInt32Contains(t *testing.T) { 69 | 70 | data := []int32{1, 2, 3} 71 | s := Int32(data) 72 | 73 | // Positive test 74 | expected := true 75 | result := s.Contains(2) 76 | if result != expected { 77 | t.Errorf("Expected '%t', but got '%t'", expected, result) 78 | } 79 | 80 | // Negative test 81 | expected = false 82 | var badValue int32 = 9 83 | result = s.Contains(badValue) 84 | if result != expected { 85 | t.Errorf("Expected '%t', but got '%t'", expected, result) 86 | } 87 | } 88 | 89 | func TestInt16Contains(t *testing.T) { 90 | 91 | data := []int16{1, 2, 3} 92 | s := Int16(data) 93 | 94 | // Positive test 95 | expected := true 96 | result := s.Contains(2) 97 | if result != expected { 98 | t.Errorf("Expected '%t', but got '%t'", expected, result) 99 | } 100 | 101 | // Negative test 102 | expected = false 103 | var badValue int16 = 9 104 | result = s.Contains(badValue) 105 | if result != expected { 106 | t.Errorf("Expected '%t', but got '%t'", expected, result) 107 | } 108 | } 109 | 110 | func TestInt8Contains(t *testing.T) { 111 | 112 | data := []int8{1, 2, 3} 113 | s := Int8(data) 114 | 115 | // Positive test 116 | expected := true 117 | result := s.Contains(2) 118 | if result != expected { 119 | t.Errorf("Expected '%t', but got '%t'", expected, result) 120 | } 121 | 122 | // Negative test 123 | expected = false 124 | var badValue int8 = 9 125 | result = s.Contains(badValue) 126 | if result != expected { 127 | t.Errorf("Expected '%t', but got '%t'", expected, result) 128 | } 129 | } 130 | 131 | func TestIntContains(t *testing.T) { 132 | 133 | data := []int{1, 2, 3} 134 | s := Int(data) 135 | 136 | // Positive test 137 | expected := true 138 | result := s.Contains(2) 139 | if result != expected { 140 | t.Errorf("Expected '%t', but got '%t'", expected, result) 141 | } 142 | 143 | // Negative test 144 | expected = false 145 | var badValue int = 9 146 | result = s.Contains(badValue) 147 | if result != expected { 148 | t.Errorf("Expected '%t', but got '%t'", expected, result) 149 | } 150 | } 151 | 152 | func TestBoolContains(t *testing.T) { 153 | 154 | data := []bool{true} 155 | s := Bool(data) 156 | 157 | // Positive test 158 | expected := true 159 | result := s.Contains(true) 160 | if result != expected { 161 | t.Errorf("Expected '%t', but got '%t'", expected, result) 162 | } 163 | 164 | // Negative test 165 | expected = false 166 | result = s.Contains(false) 167 | if result != expected { 168 | t.Errorf("Expected '%t', but got '%t'", expected, result) 169 | } 170 | } 171 | 172 | func TestFloat64Contains(t *testing.T) { 173 | 174 | data := []float64{1.4, 2.1, 3} 175 | s := Float64(data) 176 | 177 | // Positive test 178 | expected := true 179 | result := s.Contains(2.1) 180 | if result != expected { 181 | t.Errorf("Expected '%t', but got '%t'", expected, result) 182 | } 183 | 184 | // Negative test 185 | expected = false 186 | result = s.Contains(9.43) 187 | if result != expected { 188 | t.Errorf("Expected '%t', but got '%t'", expected, result) 189 | } 190 | } 191 | func TestFloat32Contains(t *testing.T) { 192 | 193 | data := []float32{1.4, 2.1, 3} 194 | s := Float32(data) 195 | 196 | // Positive test 197 | expected := true 198 | result := s.Contains(2.1) 199 | if result != expected { 200 | t.Errorf("Expected '%t', but got '%t'", expected, result) 201 | } 202 | 203 | // Negative test 204 | expected = false 205 | result = s.Contains(9.43) 206 | if result != expected { 207 | t.Errorf("Expected '%t', but got '%t'", expected, result) 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /deduplicate_test.go: -------------------------------------------------------------------------------- 1 | package slicer 2 | 3 | import ( 4 | "encoding/json" 5 | "strings" 6 | "testing" 7 | ) 8 | 9 | func TestStringDeduplicate(t *testing.T) { 10 | 11 | s := String() 12 | s.Add("one", "four", "two", "three", "two", "one") 13 | 14 | s.Deduplicate() 15 | expected := "one four two three" 16 | actual := strings.Join(s.AsSlice(), " ") 17 | if expected != actual { 18 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 19 | } 20 | } 21 | 22 | func TestInt64Deduplicate(t *testing.T) { 23 | 24 | s := Int64() 25 | s.Add(1, 2, 3, 2, 3, 4, 3, 4, 5) 26 | 27 | s.Deduplicate() 28 | expected := "[1,2,3,4,5]" 29 | actual, _ := json.Marshal(s.AsSlice()) 30 | if expected != string(actual) { 31 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 32 | } 33 | } 34 | 35 | func TestInt32Deduplicate(t *testing.T) { 36 | 37 | s := Int32() 38 | s.Add(1, 2, 3, 2, 3, 4, 3, 4, 5) 39 | 40 | s.Deduplicate() 41 | expected := "[1,2,3,4,5]" 42 | actual, _ := json.Marshal(s.AsSlice()) 43 | if expected != string(actual) { 44 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 45 | } 46 | } 47 | 48 | func TestInt16Deduplicate(t *testing.T) { 49 | 50 | s := Int16() 51 | s.Add(1, 2, 3, 2, 3, 4, 3, 4, 5) 52 | 53 | s.Deduplicate() 54 | expected := "[1,2,3,4,5]" 55 | actual, _ := json.Marshal(s.AsSlice()) 56 | if expected != string(actual) { 57 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 58 | } 59 | } 60 | 61 | func TestInt8Deduplicate(t *testing.T) { 62 | 63 | s := Int8() 64 | s.Add(1, 2, 3, 2, 3, 4, 3, 4, 5) 65 | 66 | s.Deduplicate() 67 | expected := "[1,2,3,4,5]" 68 | actual, _ := json.Marshal(s.AsSlice()) 69 | if expected != string(actual) { 70 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 71 | } 72 | } 73 | 74 | func TestIntDeduplicate(t *testing.T) { 75 | 76 | s := Int() 77 | s.Add(1, 2, 3, 2, 3, 4, 3, 4, 5) 78 | 79 | s.Deduplicate() 80 | expected := "[1,2,3,4,5]" 81 | actual, _ := json.Marshal(s.AsSlice()) 82 | if expected != string(actual) { 83 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 84 | } 85 | } 86 | 87 | func TestInterfaceDeduplicate(t *testing.T) { 88 | 89 | s := Interface() 90 | var a interface{} = 1 91 | var b interface{} = "hello" 92 | s.Add(a, b, a, b) 93 | 94 | s.Deduplicate() 95 | expected := `[1,"hello"]` 96 | actual, _ := json.Marshal(s.AsSlice()) 97 | if expected != string(actual) { 98 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 99 | } 100 | } 101 | 102 | func TestFloat32Deduplicate(t *testing.T) { 103 | 104 | s := Float32() 105 | s.Add(1.5, 2.3, 3.9, 2.3, 3.9, 4.4, 3.9, 4.4, 5.2) 106 | 107 | s.Deduplicate() 108 | expected := "[1.5,2.3,3.9,4.4,5.2]" 109 | actual, _ := json.Marshal(s.AsSlice()) 110 | if expected != string(actual) { 111 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 112 | } 113 | } 114 | 115 | func TestFloat64Deduplicate(t *testing.T) { 116 | 117 | s := Float64() 118 | s.Add(1.5, 2.3, 3.9, 2.3, 3.9, 4.4, 3.9, 4.4, 5.2) 119 | 120 | s.Deduplicate() 121 | expected := "[1.5,2.3,3.9,4.4,5.2]" 122 | actual, _ := json.Marshal(s.AsSlice()) 123 | if expected != string(actual) { 124 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 125 | } 126 | } 127 | 128 | func TestBoolDeduplicate(t *testing.T) { 129 | 130 | s := Bool() 131 | s.Add(true, true, true, false, true, false, false, false) 132 | 133 | s.Deduplicate() 134 | expected := "[true,false]" 135 | actual, _ := json.Marshal(s.AsSlice()) 136 | if expected != string(actual) { 137 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 138 | } 139 | } 140 | 141 | // func TestStringAddSlice(t *testing.T) { 142 | 143 | // s := String() 144 | // s.Add("one") 145 | // s.Add("two") 146 | // extras := []string{"three", "four"} 147 | // s.AddSlice(extras) 148 | 149 | // expected := "one two three four" 150 | // actual := strings.Join(s.AsSlice(), " ") 151 | // if expected != actual { 152 | // t.Errorf("Expected '%s', but got '%s'", expected, actual) 153 | // } 154 | // } 155 | 156 | // func TestStringAddSlicer(t *testing.T) { 157 | 158 | // s := String() 159 | // s.Add("one") 160 | // s.Add("two") 161 | 162 | // p := String() 163 | // p.Add("three") 164 | // p.Add("four") 165 | 166 | // s.AddSlicer(p) 167 | 168 | // expected := "one two three four" 169 | // actual := strings.Join(s.AsSlice(), " ") 170 | // if expected != actual { 171 | // t.Errorf("Expected '%s', but got '%s'", expected, actual) 172 | // } 173 | // } 174 | -------------------------------------------------------------------------------- /float32.go: -------------------------------------------------------------------------------- 1 | // Package slicer contains utility classes for handling slices 2 | package slicer 3 | 4 | // Imports 5 | import "sort" 6 | import "fmt" 7 | import "strings" 8 | 9 | // Float32Slicer handles slices of float32 10 | type Float32Slicer struct { 11 | slice []float32 12 | } 13 | 14 | // Float32 creates a new Float32Slicer 15 | func Float32(slice ...[]float32) *Float32Slicer { 16 | if len(slice) > 0 { 17 | return &Float32Slicer{slice: slice[0]} 18 | } 19 | return &Float32Slicer{} 20 | } 21 | 22 | // Add a float32 value to the slicer 23 | func (s *Float32Slicer) Add(value float32, additional ...float32) { 24 | s.slice = append(s.slice, value) 25 | s.slice = append(s.slice, additional...) 26 | } 27 | 28 | // AddUnique adds a float32 value to the slicer if it does not already exist 29 | func (s *Float32Slicer) AddUnique(value float32, additional ...float32) { 30 | 31 | if !s.Contains(value) { 32 | s.slice = append(s.slice, value) 33 | } 34 | 35 | // Add additional values 36 | for _, value := range additional { 37 | if !s.Contains(value) { 38 | s.slice = append(s.slice, value) 39 | } 40 | } 41 | } 42 | 43 | // AddSlice adds a float32 slice to the slicer 44 | func (s *Float32Slicer) AddSlice(value []float32) { 45 | s.slice = append(s.slice, value...) 46 | } 47 | 48 | // AsSlice returns the slice 49 | func (s *Float32Slicer) AsSlice() []float32 { 50 | return s.slice 51 | } 52 | 53 | // AddSlicer appends a Float32Slicer to the slicer 54 | func (s *Float32Slicer) AddSlicer(value *Float32Slicer) { 55 | s.slice = append(s.slice, value.AsSlice()...) 56 | } 57 | 58 | // Filter the slice based on the given function 59 | func (s *Float32Slicer) Filter(fn func(float32) bool) *Float32Slicer { 60 | result := &Float32Slicer{} 61 | for _, elem := range s.slice { 62 | if fn(elem) { 63 | result.Add(elem) 64 | } 65 | } 66 | return result 67 | } 68 | 69 | // Each runs a function on every element of the slice 70 | func (s *Float32Slicer) Each(fn func(float32)) { 71 | for _, elem := range s.slice { 72 | fn(elem) 73 | } 74 | } 75 | 76 | // Contains indicates if the given value is in the slice 77 | func (s *Float32Slicer) Contains(matcher float32) bool { 78 | result := false 79 | for _, elem := range s.slice { 80 | if elem == matcher { 81 | result = true 82 | } 83 | } 84 | return result 85 | } 86 | 87 | // Length returns the number of elements in the slice 88 | func (s *Float32Slicer) Length() int { 89 | return len(s.slice) 90 | } 91 | 92 | // Clear all elements in the slice 93 | func (s *Float32Slicer) Clear() { 94 | s.slice = []float32{} 95 | } 96 | 97 | // Deduplicate removes duplicate values from the slice 98 | func (s *Float32Slicer) Deduplicate() { 99 | 100 | result := &Float32Slicer{} 101 | 102 | for _, elem := range s.slice { 103 | if !result.Contains(elem) { 104 | result.Add(elem) 105 | } 106 | } 107 | 108 | s.slice = result.AsSlice() 109 | } 110 | 111 | // Join returns a string with the slicer elements separated by the given separator 112 | func (s *Float32Slicer) Join(separator string) string { 113 | var builder strings.Builder 114 | 115 | // Shortcut no elements 116 | if len(s.slice) == 0 { 117 | return "" 118 | } 119 | 120 | // Iterate over length - 1 121 | index := 0 122 | for index = 0; index < len(s.slice)-1; index++ { 123 | builder.WriteString(fmt.Sprintf("%v%s", s.slice[index], separator)) 124 | } 125 | builder.WriteString(fmt.Sprintf("%v", s.slice[index])) 126 | result := builder.String() 127 | return result 128 | } 129 | 130 | // Sort the slice values 131 | func (s *Float32Slicer) Sort() { 132 | sort.Slice(s.slice, func(i, j int) bool { return s.slice[i] < s.slice[j] }) 133 | } 134 | -------------------------------------------------------------------------------- /float32_test.go: -------------------------------------------------------------------------------- 1 | package slicer 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "testing" 7 | ) 8 | 9 | func TestFloat32Add(t *testing.T) { 10 | 11 | s := Float32() 12 | s.Add(1.1) 13 | s.Add(2.5) 14 | 15 | expected := "[1.1,2.5]" 16 | actual, _ := json.Marshal(s.AsSlice()) 17 | if expected != string(actual) { 18 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 19 | } 20 | 21 | s.Clear() 22 | s.Add(1.1, 2.5) 23 | 24 | expected = "[1.1,2.5]" 25 | actual, _ = json.Marshal(s.AsSlice()) 26 | if expected != string(actual) { 27 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 28 | } 29 | } 30 | func TestFloat32AddUnique(t *testing.T) { 31 | 32 | s := Float32() 33 | s.AddUnique(1.1) 34 | s.AddUnique(1.1) 35 | s.AddUnique(2.5) 36 | 37 | expected := "[1.1,2.5]" 38 | actual, _ := json.Marshal(s.AsSlice()) 39 | if expected != string(actual) { 40 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 41 | } 42 | 43 | s.Clear() 44 | s.AddUnique(1.1, 2.5, 2.5) 45 | 46 | expected = "[1.1,2.5]" 47 | actual, _ = json.Marshal(s.AsSlice()) 48 | if expected != string(actual) { 49 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 50 | } 51 | } 52 | 53 | func TestFloat32AddSlice(t *testing.T) { 54 | 55 | s := Float32() 56 | s.Add(1.1) 57 | s.Add(2.2) 58 | 59 | extras := []float32{3.3, 4.4} 60 | 61 | s.AddSlice(extras) 62 | 63 | expected := "[1.1,2.2,3.3,4.4]" 64 | actual, _ := json.Marshal(s.AsSlice()) 65 | if expected != string(actual) { 66 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 67 | } 68 | } 69 | 70 | func TestFloat32AddSlicer(t *testing.T) { 71 | 72 | s := Float32() 73 | s.Add(1.1) 74 | s.Add(2.2) 75 | 76 | p := Float32() 77 | p.Add(3.3) 78 | p.Add(4.4) 79 | 80 | s.AddSlicer(p) 81 | 82 | expected := "[1.1,2.2,3.3,4.4]" 83 | actual, _ := json.Marshal(s.AsSlice()) 84 | if expected != string(actual) { 85 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 86 | } 87 | } 88 | 89 | func TestFloat32Filter(t *testing.T) { 90 | 91 | s := Float32() 92 | s.Add(0.1) 93 | s.Add(0.4) 94 | s.Add(0.3) 95 | s.Add(0.8) 96 | s.Add(0.5) 97 | s.Add(1.3) 98 | s.Add(3.9) 99 | s.Add(0.4) 100 | 101 | result := s.Filter(func(i float32) bool { 102 | return i < 0.5 103 | }) 104 | 105 | expected := "[0.1,0.4,0.3,0.4]" 106 | actual, _ := json.Marshal(result.AsSlice()) 107 | if expected != string(actual) { 108 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 109 | } 110 | } 111 | 112 | func TestFloat32Each(t *testing.T) { 113 | 114 | s := Float32() 115 | s.Add(0.1) 116 | s.Add(0.4) 117 | s.Add(0.3) 118 | s.Add(0.8) 119 | s.Add(0.5) 120 | s.Add(1.3) 121 | s.Add(3.9) 122 | s.Add(0.4) 123 | 124 | var result float32 125 | s.Each(func(i float32) { 126 | result += i 127 | }) 128 | 129 | var expected = 7.7 130 | if fmt.Sprintf("%f", expected) != fmt.Sprintf("%f", result) { 131 | t.Errorf("Expected '%f', but got '%f'", expected, result) 132 | } 133 | } 134 | 135 | // TestOptionalFloat32Slice tests when you construct a Float32 with 136 | // an existing slice 137 | func TestOptionalFloat32Slice(t *testing.T) { 138 | data := []float32{1, 2, 3} 139 | s := Float32(data) 140 | 141 | var result float32 142 | s.Each(func(elem float32) { 143 | result += elem 144 | }) 145 | var expected float32 = 6.0 146 | if expected != result { 147 | t.Errorf("Expected '%f', but got '%f'", expected, result) 148 | } 149 | } 150 | 151 | // TestFloat32Sort tests that the slicer can be sorted 152 | func TestFloat32Sort(t *testing.T) { 153 | data := []float32{5, 4, 3, 2, 1} 154 | s := Float32(data) 155 | s.Sort() 156 | result := s.Join(",") 157 | expected := "1,2,3,4,5" 158 | if expected != result { 159 | t.Errorf("Expected '%s', but got '%s'", expected, result) 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /float64.go: -------------------------------------------------------------------------------- 1 | // Package slicer contains utility classes for handling slices 2 | package slicer 3 | 4 | // Imports 5 | import "sort" 6 | import "fmt" 7 | import "strings" 8 | 9 | // Float64Slicer handles slices of float64 10 | type Float64Slicer struct { 11 | slice []float64 12 | } 13 | 14 | // Float64 creates a new Float64Slicer 15 | func Float64(slice ...[]float64) *Float64Slicer { 16 | if len(slice) > 0 { 17 | return &Float64Slicer{slice: slice[0]} 18 | } 19 | return &Float64Slicer{} 20 | } 21 | 22 | // Add a float64 value to the slicer 23 | func (s *Float64Slicer) Add(value float64, additional ...float64) { 24 | s.slice = append(s.slice, value) 25 | s.slice = append(s.slice, additional...) 26 | } 27 | 28 | // AddUnique adds a float64 value to the slicer if it does not already exist 29 | func (s *Float64Slicer) AddUnique(value float64, additional ...float64) { 30 | 31 | if !s.Contains(value) { 32 | s.slice = append(s.slice, value) 33 | } 34 | 35 | // Add additional values 36 | for _, value := range additional { 37 | if !s.Contains(value) { 38 | s.slice = append(s.slice, value) 39 | } 40 | } 41 | } 42 | 43 | // AddSlice adds a float64 slice to the slicer 44 | func (s *Float64Slicer) AddSlice(value []float64) { 45 | s.slice = append(s.slice, value...) 46 | } 47 | 48 | // AsSlice returns the slice 49 | func (s *Float64Slicer) AsSlice() []float64 { 50 | return s.slice 51 | } 52 | 53 | // AddSlicer appends a Float64Slicer to the slicer 54 | func (s *Float64Slicer) AddSlicer(value *Float64Slicer) { 55 | s.slice = append(s.slice, value.AsSlice()...) 56 | } 57 | 58 | // Filter the slice based on the given function 59 | func (s *Float64Slicer) Filter(fn func(float64) bool) *Float64Slicer { 60 | result := &Float64Slicer{} 61 | for _, elem := range s.slice { 62 | if fn(elem) { 63 | result.Add(elem) 64 | } 65 | } 66 | return result 67 | } 68 | 69 | // Each runs a function on every element of the slice 70 | func (s *Float64Slicer) Each(fn func(float64)) { 71 | for _, elem := range s.slice { 72 | fn(elem) 73 | } 74 | } 75 | 76 | // Contains indicates if the given value is in the slice 77 | func (s *Float64Slicer) Contains(matcher float64) bool { 78 | result := false 79 | for _, elem := range s.slice { 80 | if elem == matcher { 81 | result = true 82 | } 83 | } 84 | return result 85 | } 86 | 87 | // Length returns the number of elements in the slice 88 | func (s *Float64Slicer) Length() int { 89 | return len(s.slice) 90 | } 91 | 92 | // Clear all elements in the slice 93 | func (s *Float64Slicer) Clear() { 94 | s.slice = []float64{} 95 | } 96 | 97 | // Deduplicate removes duplicate values from the slice 98 | func (s *Float64Slicer) Deduplicate() { 99 | 100 | result := &Float64Slicer{} 101 | 102 | for _, elem := range s.slice { 103 | if !result.Contains(elem) { 104 | result.Add(elem) 105 | } 106 | } 107 | 108 | s.slice = result.AsSlice() 109 | } 110 | 111 | // Join returns a string with the slicer elements separated by the given separator 112 | func (s *Float64Slicer) Join(separator string) string { 113 | var builder strings.Builder 114 | 115 | // Shortcut no elements 116 | if len(s.slice) == 0 { 117 | return "" 118 | } 119 | 120 | // Iterate over length - 1 121 | index := 0 122 | for index = 0; index < len(s.slice)-1; index++ { 123 | builder.WriteString(fmt.Sprintf("%v%s", s.slice[index], separator)) 124 | } 125 | builder.WriteString(fmt.Sprintf("%v", s.slice[index])) 126 | result := builder.String() 127 | return result 128 | } 129 | 130 | // Sort the slice values 131 | func (s *Float64Slicer) Sort() { 132 | sort.Slice(s.slice, func(i, j int) bool { return s.slice[i] < s.slice[j] }) 133 | } 134 | -------------------------------------------------------------------------------- /float64_test.go: -------------------------------------------------------------------------------- 1 | package slicer 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "testing" 7 | ) 8 | 9 | func TestFloat64Add(t *testing.T) { 10 | 11 | s := Float64() 12 | s.Add(1.1) 13 | s.Add(2.5) 14 | 15 | expected := "[1.1,2.5]" 16 | actual, _ := json.Marshal(s.AsSlice()) 17 | if expected != string(actual) { 18 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 19 | } 20 | s.Clear() 21 | s.Add(1.1, 2.5) 22 | 23 | expected = "[1.1,2.5]" 24 | actual, _ = json.Marshal(s.AsSlice()) 25 | if expected != string(actual) { 26 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 27 | } 28 | } 29 | func TestFloat64AddUnique(t *testing.T) { 30 | 31 | s := Float64() 32 | s.AddUnique(1.1) 33 | s.AddUnique(2.5) 34 | s.AddUnique(2.5) 35 | 36 | expected := "[1.1,2.5]" 37 | actual, _ := json.Marshal(s.AsSlice()) 38 | if expected != string(actual) { 39 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 40 | } 41 | s.Clear() 42 | s.AddUnique(1.1, 2.5, 1.1) 43 | 44 | expected = "[1.1,2.5]" 45 | actual, _ = json.Marshal(s.AsSlice()) 46 | if expected != string(actual) { 47 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 48 | } 49 | } 50 | 51 | func TestFloat64AddSlice(t *testing.T) { 52 | 53 | s := Float64() 54 | s.Add(1.1) 55 | s.Add(2.2) 56 | 57 | extras := []float64{3.3, 4.4} 58 | 59 | s.AddSlice(extras) 60 | 61 | expected := "[1.1,2.2,3.3,4.4]" 62 | actual, _ := json.Marshal(s.AsSlice()) 63 | if expected != string(actual) { 64 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 65 | } 66 | } 67 | 68 | func TestFloat64AddSlicer(t *testing.T) { 69 | 70 | s := Float64() 71 | s.Add(1.1) 72 | s.Add(2.2) 73 | 74 | p := Float64() 75 | p.Add(3.3) 76 | p.Add(4.4) 77 | 78 | s.AddSlicer(p) 79 | 80 | expected := "[1.1,2.2,3.3,4.4]" 81 | actual, _ := json.Marshal(s.AsSlice()) 82 | if expected != string(actual) { 83 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 84 | } 85 | } 86 | 87 | func TestFloat64Filter(t *testing.T) { 88 | 89 | s := Float64() 90 | s.Add(0.1) 91 | s.Add(0.4) 92 | s.Add(0.3) 93 | s.Add(0.8) 94 | s.Add(0.5) 95 | s.Add(1.3) 96 | s.Add(3.9) 97 | s.Add(0.4) 98 | 99 | result := s.Filter(func(i float64) bool { 100 | return i < 0.5 101 | }) 102 | 103 | expected := "[0.1,0.4,0.3,0.4]" 104 | actual, _ := json.Marshal(result.AsSlice()) 105 | if expected != string(actual) { 106 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 107 | } 108 | } 109 | 110 | func TestFloat64Each(t *testing.T) { 111 | 112 | s := Float64() 113 | s.Add(0.1) 114 | s.Add(0.4) 115 | s.Add(0.3) 116 | s.Add(0.8) 117 | s.Add(0.5) 118 | s.Add(1.3) 119 | s.Add(3.9) 120 | s.Add(0.4) 121 | 122 | var result float64 123 | s.Each(func(i float64) { 124 | result += i 125 | }) 126 | 127 | var expected = 7.7 128 | if fmt.Sprintf("%f", expected) != fmt.Sprintf("%f", result) { 129 | t.Errorf("Expected '%f', but got '%f'", expected, result) 130 | } 131 | } 132 | 133 | // TestOptionalFloat64Slice tests when you construct a Float64 with 134 | // an existing slice 135 | func TestOptionalFloat64Slice(t *testing.T) { 136 | data := []float64{1, 2, 3} 137 | s := Float64(data) 138 | 139 | var result float64 140 | s.Each(func(elem float64) { 141 | result += elem 142 | }) 143 | var expected = 6.0 144 | if expected != result { 145 | t.Errorf("Expected '%f', but got '%f'", expected, result) 146 | } 147 | } 148 | 149 | // TestFloat64Sort tests that the slicer can be sorted 150 | func TestFloat64Sort(t *testing.T) { 151 | data := []float64{5, 4, 3, 2, 1} 152 | s := Float64(data) 153 | s.Sort() 154 | result := s.Join(",") 155 | expected := "1,2,3,4,5" 156 | if expected != result { 157 | t.Errorf("Expected '%s', but got '%s'", expected, result) 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/leaanthony/slicer 2 | 3 | go 1.13 4 | 5 | require github.com/matryer/is v1.4.0 6 | -------------------------------------------------------------------------------- /int.go: -------------------------------------------------------------------------------- 1 | // Package slicer contains utility classes for handling slices 2 | package slicer 3 | 4 | // Imports 5 | import "sort" 6 | import "fmt" 7 | import "strings" 8 | 9 | // IntSlicer handles slices of int 10 | type IntSlicer struct { 11 | slice []int 12 | } 13 | 14 | // Int creates a new IntSlicer 15 | func Int(slice ...[]int) *IntSlicer { 16 | if len(slice) > 0 { 17 | return &IntSlicer{slice: slice[0]} 18 | } 19 | return &IntSlicer{} 20 | } 21 | 22 | // Add a int value to the slicer 23 | func (s *IntSlicer) Add(value int, additional ...int) { 24 | s.slice = append(s.slice, value) 25 | s.slice = append(s.slice, additional...) 26 | } 27 | 28 | // AddUnique adds a int value to the slicer if it does not already exist 29 | func (s *IntSlicer) AddUnique(value int, additional ...int) { 30 | 31 | if !s.Contains(value) { 32 | s.slice = append(s.slice, value) 33 | } 34 | 35 | // Add additional values 36 | for _, value := range additional { 37 | if !s.Contains(value) { 38 | s.slice = append(s.slice, value) 39 | } 40 | } 41 | } 42 | 43 | // AddSlice adds a int slice to the slicer 44 | func (s *IntSlicer) AddSlice(value []int) { 45 | s.slice = append(s.slice, value...) 46 | } 47 | 48 | // AsSlice returns the slice 49 | func (s *IntSlicer) AsSlice() []int { 50 | return s.slice 51 | } 52 | 53 | // AddSlicer appends a IntSlicer to the slicer 54 | func (s *IntSlicer) AddSlicer(value *IntSlicer) { 55 | s.slice = append(s.slice, value.AsSlice()...) 56 | } 57 | 58 | // Filter the slice based on the given function 59 | func (s *IntSlicer) Filter(fn func(int) bool) *IntSlicer { 60 | result := &IntSlicer{} 61 | for _, elem := range s.slice { 62 | if fn(elem) { 63 | result.Add(elem) 64 | } 65 | } 66 | return result 67 | } 68 | 69 | // Each runs a function on every element of the slice 70 | func (s *IntSlicer) Each(fn func(int)) { 71 | for _, elem := range s.slice { 72 | fn(elem) 73 | } 74 | } 75 | 76 | // Contains indicates if the given value is in the slice 77 | func (s *IntSlicer) Contains(matcher int) bool { 78 | result := false 79 | for _, elem := range s.slice { 80 | if elem == matcher { 81 | result = true 82 | } 83 | } 84 | return result 85 | } 86 | 87 | // Length returns the number of elements in the slice 88 | func (s *IntSlicer) Length() int { 89 | return len(s.slice) 90 | } 91 | 92 | // Clear all elements in the slice 93 | func (s *IntSlicer) Clear() { 94 | s.slice = []int{} 95 | } 96 | 97 | // Deduplicate removes duplicate values from the slice 98 | func (s *IntSlicer) Deduplicate() { 99 | 100 | result := &IntSlicer{} 101 | 102 | for _, elem := range s.slice { 103 | if !result.Contains(elem) { 104 | result.Add(elem) 105 | } 106 | } 107 | 108 | s.slice = result.AsSlice() 109 | } 110 | 111 | // Join returns a string with the slicer elements separated by the given separator 112 | func (s *IntSlicer) Join(separator string) string { 113 | var builder strings.Builder 114 | 115 | // Shortcut no elements 116 | if len(s.slice) == 0 { 117 | return "" 118 | } 119 | 120 | // Iterate over length - 1 121 | index := 0 122 | for index = 0; index < len(s.slice)-1; index++ { 123 | builder.WriteString(fmt.Sprintf("%v%s", s.slice[index], separator)) 124 | } 125 | builder.WriteString(fmt.Sprintf("%v", s.slice[index])) 126 | result := builder.String() 127 | return result 128 | } 129 | 130 | // Sort the slice values 131 | func (s *IntSlicer) Sort() { 132 | sort.Slice(s.slice, func(i, j int) bool { return s.slice[i] < s.slice[j] }) 133 | } 134 | -------------------------------------------------------------------------------- /int16.go: -------------------------------------------------------------------------------- 1 | // Package slicer contains utility classes for handling slices 2 | package slicer 3 | 4 | // Imports 5 | import "sort" 6 | import "fmt" 7 | import "strings" 8 | 9 | // Int16Slicer handles slices of int16 10 | type Int16Slicer struct { 11 | slice []int16 12 | } 13 | 14 | // Int16 creates a new Int16Slicer 15 | func Int16(slice ...[]int16) *Int16Slicer { 16 | if len(slice) > 0 { 17 | return &Int16Slicer{slice: slice[0]} 18 | } 19 | return &Int16Slicer{} 20 | } 21 | 22 | // Add a int16 value to the slicer 23 | func (s *Int16Slicer) Add(value int16, additional ...int16) { 24 | s.slice = append(s.slice, value) 25 | s.slice = append(s.slice, additional...) 26 | } 27 | 28 | // AddUnique adds a int16 value to the slicer if it does not already exist 29 | func (s *Int16Slicer) AddUnique(value int16, additional ...int16) { 30 | 31 | if !s.Contains(value) { 32 | s.slice = append(s.slice, value) 33 | } 34 | 35 | // Add additional values 36 | for _, value := range additional { 37 | if !s.Contains(value) { 38 | s.slice = append(s.slice, value) 39 | } 40 | } 41 | } 42 | 43 | // AddSlice adds a int16 slice to the slicer 44 | func (s *Int16Slicer) AddSlice(value []int16) { 45 | s.slice = append(s.slice, value...) 46 | } 47 | 48 | // AsSlice returns the slice 49 | func (s *Int16Slicer) AsSlice() []int16 { 50 | return s.slice 51 | } 52 | 53 | // AddSlicer appends a Int16Slicer to the slicer 54 | func (s *Int16Slicer) AddSlicer(value *Int16Slicer) { 55 | s.slice = append(s.slice, value.AsSlice()...) 56 | } 57 | 58 | // Filter the slice based on the given function 59 | func (s *Int16Slicer) Filter(fn func(int16) bool) *Int16Slicer { 60 | result := &Int16Slicer{} 61 | for _, elem := range s.slice { 62 | if fn(elem) { 63 | result.Add(elem) 64 | } 65 | } 66 | return result 67 | } 68 | 69 | // Each runs a function on every element of the slice 70 | func (s *Int16Slicer) Each(fn func(int16)) { 71 | for _, elem := range s.slice { 72 | fn(elem) 73 | } 74 | } 75 | 76 | // Contains indicates if the given value is in the slice 77 | func (s *Int16Slicer) Contains(matcher int16) bool { 78 | result := false 79 | for _, elem := range s.slice { 80 | if elem == matcher { 81 | result = true 82 | } 83 | } 84 | return result 85 | } 86 | 87 | // Length returns the number of elements in the slice 88 | func (s *Int16Slicer) Length() int { 89 | return len(s.slice) 90 | } 91 | 92 | // Clear all elements in the slice 93 | func (s *Int16Slicer) Clear() { 94 | s.slice = []int16{} 95 | } 96 | 97 | // Deduplicate removes duplicate values from the slice 98 | func (s *Int16Slicer) Deduplicate() { 99 | 100 | result := &Int16Slicer{} 101 | 102 | for _, elem := range s.slice { 103 | if !result.Contains(elem) { 104 | result.Add(elem) 105 | } 106 | } 107 | 108 | s.slice = result.AsSlice() 109 | } 110 | 111 | // Join returns a string with the slicer elements separated by the given separator 112 | func (s *Int16Slicer) Join(separator string) string { 113 | var builder strings.Builder 114 | 115 | // Shortcut no elements 116 | if len(s.slice) == 0 { 117 | return "" 118 | } 119 | 120 | // Iterate over length - 1 121 | index := 0 122 | for index = 0; index < len(s.slice)-1; index++ { 123 | builder.WriteString(fmt.Sprintf("%v%s", s.slice[index], separator)) 124 | } 125 | builder.WriteString(fmt.Sprintf("%v", s.slice[index])) 126 | result := builder.String() 127 | return result 128 | } 129 | 130 | // Sort the slice values 131 | func (s *Int16Slicer) Sort() { 132 | sort.Slice(s.slice, func(i, j int) bool { return s.slice[i] < s.slice[j] }) 133 | } 134 | -------------------------------------------------------------------------------- /int16_test.go: -------------------------------------------------------------------------------- 1 | package slicer 2 | 3 | import ( 4 | "encoding/json" 5 | "testing" 6 | ) 7 | 8 | func TestInt16Add(t *testing.T) { 9 | 10 | s := Int16() 11 | s.Add(1) 12 | s.Add(2) 13 | 14 | expected := "[1,2]" 15 | actual, _ := json.Marshal(s.AsSlice()) 16 | if expected != string(actual) { 17 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 18 | } 19 | 20 | s.Clear() 21 | s.Add(1, 2) 22 | 23 | expected = "[1,2]" 24 | actual, _ = json.Marshal(s.AsSlice()) 25 | if expected != string(actual) { 26 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 27 | } 28 | } 29 | 30 | func TestInt16AddUnique(t *testing.T) { 31 | 32 | s := Int16() 33 | s.AddUnique(1) 34 | s.AddUnique(2) 35 | s.AddUnique(2) 36 | s.AddUnique(2) 37 | 38 | expected := "[1,2]" 39 | actual, _ := json.Marshal(s.AsSlice()) 40 | if expected != string(actual) { 41 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 42 | } 43 | 44 | s.Clear() 45 | s.AddUnique(1, 2, 1, 2, 2, 1) 46 | 47 | expected = "[1,2]" 48 | actual, _ = json.Marshal(s.AsSlice()) 49 | if expected != string(actual) { 50 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 51 | } 52 | } 53 | 54 | func TestInt16AddSlice(t *testing.T) { 55 | 56 | s := Int16() 57 | s.Add(1) 58 | s.Add(2) 59 | 60 | extras := []int16{3, 4} 61 | 62 | s.AddSlice(extras) 63 | 64 | expected := "[1,2,3,4]" 65 | actual, _ := json.Marshal(s.AsSlice()) 66 | if expected != string(actual) { 67 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 68 | } 69 | } 70 | 71 | func TestInt16AddSlicer(t *testing.T) { 72 | 73 | s := Int16() 74 | s.Add(1) 75 | s.Add(2) 76 | 77 | p := Int16() 78 | p.Add(3) 79 | p.Add(4) 80 | 81 | s.AddSlicer(p) 82 | 83 | expected := "[1,2,3,4]" 84 | actual, _ := json.Marshal(s.AsSlice()) 85 | if expected != string(actual) { 86 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 87 | } 88 | } 89 | func TestInt16Filter(t *testing.T) { 90 | 91 | s := Int16() 92 | s.Add(18) 93 | s.Add(180) 94 | s.Add(1) 95 | s.Add(10) 96 | s.Add(20) 97 | s.Add(3) 98 | s.Add(29) 99 | 100 | result := s.Filter(func(i int16) bool { 101 | return i > 19 102 | }) 103 | 104 | expected := "[180,20,29]" 105 | actual, _ := json.Marshal(result.AsSlice()) 106 | if expected != string(actual) { 107 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 108 | } 109 | } 110 | func TestInt16Each(t *testing.T) { 111 | 112 | s := Int16() 113 | s.Add(18) 114 | s.Add(10) 115 | s.Add(1) 116 | s.Add(10) 117 | s.Add(20) 118 | s.Add(3) 119 | s.Add(29) 120 | 121 | var result int16 122 | 123 | s.Each(func(i int16) { 124 | result = result + i 125 | }) 126 | 127 | var expected int16 = 91 128 | if expected != result { 129 | t.Errorf("Expected '%d', but got '%d'", expected, result) 130 | } 131 | } 132 | 133 | // TestOptionalInt16Slice tests when you construct a Int16 with 134 | // an existing slice 135 | func TestOptionalInt16Slice(t *testing.T) { 136 | data := []int16{1, 2, 3} 137 | s := Int16(data) 138 | 139 | var result int16 = 0 140 | s.Each(func(elem int16) { 141 | result += elem 142 | }) 143 | var expected int16 = 6 144 | if expected != result { 145 | t.Errorf("Expected '%d', but got '%d'", expected, result) 146 | } 147 | } 148 | 149 | // TestInt16Sort tests that the slicer can be sorted 150 | func TestInt16Sort(t *testing.T) { 151 | data := []int16{5, 4, 3, 2, 1} 152 | s := Int16(data) 153 | s.Sort() 154 | result := s.Join(",") 155 | expected := "1,2,3,4,5" 156 | if expected != result { 157 | t.Errorf("Expected '%s', but got '%s'", expected, result) 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /int32.go: -------------------------------------------------------------------------------- 1 | // Package slicer contains utility classes for handling slices 2 | package slicer 3 | 4 | // Imports 5 | import "sort" 6 | import "fmt" 7 | import "strings" 8 | 9 | // Int32Slicer handles slices of int32 10 | type Int32Slicer struct { 11 | slice []int32 12 | } 13 | 14 | // Int32 creates a new Int32Slicer 15 | func Int32(slice ...[]int32) *Int32Slicer { 16 | if len(slice) > 0 { 17 | return &Int32Slicer{slice: slice[0]} 18 | } 19 | return &Int32Slicer{} 20 | } 21 | 22 | // Add a int32 value to the slicer 23 | func (s *Int32Slicer) Add(value int32, additional ...int32) { 24 | s.slice = append(s.slice, value) 25 | s.slice = append(s.slice, additional...) 26 | } 27 | 28 | // AddUnique adds a int32 value to the slicer if it does not already exist 29 | func (s *Int32Slicer) AddUnique(value int32, additional ...int32) { 30 | 31 | if !s.Contains(value) { 32 | s.slice = append(s.slice, value) 33 | } 34 | 35 | // Add additional values 36 | for _, value := range additional { 37 | if !s.Contains(value) { 38 | s.slice = append(s.slice, value) 39 | } 40 | } 41 | } 42 | 43 | // AddSlice adds a int32 slice to the slicer 44 | func (s *Int32Slicer) AddSlice(value []int32) { 45 | s.slice = append(s.slice, value...) 46 | } 47 | 48 | // AsSlice returns the slice 49 | func (s *Int32Slicer) AsSlice() []int32 { 50 | return s.slice 51 | } 52 | 53 | // AddSlicer appends a Int32Slicer to the slicer 54 | func (s *Int32Slicer) AddSlicer(value *Int32Slicer) { 55 | s.slice = append(s.slice, value.AsSlice()...) 56 | } 57 | 58 | // Filter the slice based on the given function 59 | func (s *Int32Slicer) Filter(fn func(int32) bool) *Int32Slicer { 60 | result := &Int32Slicer{} 61 | for _, elem := range s.slice { 62 | if fn(elem) { 63 | result.Add(elem) 64 | } 65 | } 66 | return result 67 | } 68 | 69 | // Each runs a function on every element of the slice 70 | func (s *Int32Slicer) Each(fn func(int32)) { 71 | for _, elem := range s.slice { 72 | fn(elem) 73 | } 74 | } 75 | 76 | // Contains indicates if the given value is in the slice 77 | func (s *Int32Slicer) Contains(matcher int32) bool { 78 | result := false 79 | for _, elem := range s.slice { 80 | if elem == matcher { 81 | result = true 82 | } 83 | } 84 | return result 85 | } 86 | 87 | // Length returns the number of elements in the slice 88 | func (s *Int32Slicer) Length() int { 89 | return len(s.slice) 90 | } 91 | 92 | // Clear all elements in the slice 93 | func (s *Int32Slicer) Clear() { 94 | s.slice = []int32{} 95 | } 96 | 97 | // Deduplicate removes duplicate values from the slice 98 | func (s *Int32Slicer) Deduplicate() { 99 | 100 | result := &Int32Slicer{} 101 | 102 | for _, elem := range s.slice { 103 | if !result.Contains(elem) { 104 | result.Add(elem) 105 | } 106 | } 107 | 108 | s.slice = result.AsSlice() 109 | } 110 | 111 | // Join returns a string with the slicer elements separated by the given separator 112 | func (s *Int32Slicer) Join(separator string) string { 113 | var builder strings.Builder 114 | 115 | // Shortcut no elements 116 | if len(s.slice) == 0 { 117 | return "" 118 | } 119 | 120 | // Iterate over length - 1 121 | index := 0 122 | for index = 0; index < len(s.slice)-1; index++ { 123 | builder.WriteString(fmt.Sprintf("%v%s", s.slice[index], separator)) 124 | } 125 | builder.WriteString(fmt.Sprintf("%v", s.slice[index])) 126 | result := builder.String() 127 | return result 128 | } 129 | 130 | // Sort the slice values 131 | func (s *Int32Slicer) Sort() { 132 | sort.Slice(s.slice, func(i, j int) bool { return s.slice[i] < s.slice[j] }) 133 | } 134 | -------------------------------------------------------------------------------- /int32_test.go: -------------------------------------------------------------------------------- 1 | package slicer 2 | 3 | import ( 4 | "encoding/json" 5 | "testing" 6 | ) 7 | 8 | func TestInt32Add(t *testing.T) { 9 | 10 | s := Int32() 11 | s.Add(1) 12 | s.Add(2) 13 | 14 | expected := "[1,2]" 15 | actual, _ := json.Marshal(s.AsSlice()) 16 | if expected != string(actual) { 17 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 18 | } 19 | s.Clear() 20 | s.Add(1, 2) 21 | 22 | expected = "[1,2]" 23 | actual, _ = json.Marshal(s.AsSlice()) 24 | if expected != string(actual) { 25 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 26 | } 27 | } 28 | 29 | func TestInt32AddUnique(t *testing.T) { 30 | 31 | s := Int32() 32 | s.AddUnique(1) 33 | s.AddUnique(2) 34 | s.AddUnique(2) 35 | s.AddUnique(2) 36 | 37 | expected := "[1,2]" 38 | actual, _ := json.Marshal(s.AsSlice()) 39 | if expected != string(actual) { 40 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 41 | } 42 | 43 | s.Clear() 44 | s.AddUnique(1, 2, 1, 2, 2, 1) 45 | 46 | expected = "[1,2]" 47 | actual, _ = json.Marshal(s.AsSlice()) 48 | if expected != string(actual) { 49 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 50 | } 51 | } 52 | 53 | func TestInt32AddSlice(t *testing.T) { 54 | 55 | s := Int32() 56 | s.Add(1) 57 | s.Add(2) 58 | 59 | extras := []int32{3, 4} 60 | 61 | s.AddSlice(extras) 62 | 63 | expected := "[1,2,3,4]" 64 | actual, _ := json.Marshal(s.AsSlice()) 65 | if expected != string(actual) { 66 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 67 | } 68 | } 69 | 70 | func TestInt32AddSlicer(t *testing.T) { 71 | 72 | s := Int32() 73 | s.Add(1) 74 | s.Add(2) 75 | 76 | p := Int32() 77 | p.Add(3) 78 | p.Add(4) 79 | 80 | s.AddSlicer(p) 81 | 82 | expected := "[1,2,3,4]" 83 | actual, _ := json.Marshal(s.AsSlice()) 84 | if expected != string(actual) { 85 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 86 | } 87 | } 88 | 89 | func TestInt32Filter(t *testing.T) { 90 | 91 | s := Int32() 92 | s.Add(18) 93 | s.Add(180) 94 | s.Add(1) 95 | s.Add(10) 96 | s.Add(20) 97 | s.Add(3) 98 | s.Add(29) 99 | 100 | result := s.Filter(func(i int32) bool { 101 | return i > 19 102 | }) 103 | 104 | expected := "[180,20,29]" 105 | actual, _ := json.Marshal(result.AsSlice()) 106 | if expected != string(actual) { 107 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 108 | } 109 | } 110 | 111 | func TestInt32Each(t *testing.T) { 112 | 113 | s := Int32() 114 | s.Add(18) 115 | s.Add(10) 116 | s.Add(1) 117 | s.Add(10) 118 | s.Add(20) 119 | s.Add(3) 120 | s.Add(29) 121 | 122 | var result int32 123 | 124 | s.Each(func(i int32) { 125 | result = result + i 126 | }) 127 | 128 | var expected int32 = 91 129 | if expected != result { 130 | t.Errorf("Expected '%d', but got '%d'", expected, result) 131 | } 132 | } 133 | 134 | // TestOptionalInt32Slice tests when you construct a Int32 with 135 | // an existing slice 136 | func TestOptionalInt32Slice(t *testing.T) { 137 | data := []int32{1, 2, 3} 138 | s := Int32(data) 139 | 140 | var result int32 = 0 141 | s.Each(func(elem int32) { 142 | result += elem 143 | }) 144 | var expected int32 = 6 145 | if expected != result { 146 | t.Errorf("Expected '%d', but got '%d'", expected, result) 147 | } 148 | } 149 | 150 | // TestInt32Sort tests that the slicer can be sorted 151 | func TestInt32Sort(t *testing.T) { 152 | data := []int32{5, 4, 3, 2, 1} 153 | s := Int32(data) 154 | s.Sort() 155 | result := s.Join(",") 156 | expected := "1,2,3,4,5" 157 | if expected != result { 158 | t.Errorf("Expected '%s', but got '%s'", expected, result) 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /int64.go: -------------------------------------------------------------------------------- 1 | // Package slicer contains utility classes for handling slices 2 | package slicer 3 | 4 | // Imports 5 | import "sort" 6 | import "fmt" 7 | import "strings" 8 | 9 | // Int64Slicer handles slices of int64 10 | type Int64Slicer struct { 11 | slice []int64 12 | } 13 | 14 | // Int64 creates a new Int64Slicer 15 | func Int64(slice ...[]int64) *Int64Slicer { 16 | if len(slice) > 0 { 17 | return &Int64Slicer{slice: slice[0]} 18 | } 19 | return &Int64Slicer{} 20 | } 21 | 22 | // Add a int64 value to the slicer 23 | func (s *Int64Slicer) Add(value int64, additional ...int64) { 24 | s.slice = append(s.slice, value) 25 | s.slice = append(s.slice, additional...) 26 | } 27 | 28 | // AddUnique adds a int64 value to the slicer if it does not already exist 29 | func (s *Int64Slicer) AddUnique(value int64, additional ...int64) { 30 | 31 | if !s.Contains(value) { 32 | s.slice = append(s.slice, value) 33 | } 34 | 35 | // Add additional values 36 | for _, value := range additional { 37 | if !s.Contains(value) { 38 | s.slice = append(s.slice, value) 39 | } 40 | } 41 | } 42 | 43 | // AddSlice adds a int64 slice to the slicer 44 | func (s *Int64Slicer) AddSlice(value []int64) { 45 | s.slice = append(s.slice, value...) 46 | } 47 | 48 | // AsSlice returns the slice 49 | func (s *Int64Slicer) AsSlice() []int64 { 50 | return s.slice 51 | } 52 | 53 | // AddSlicer appends a Int64Slicer to the slicer 54 | func (s *Int64Slicer) AddSlicer(value *Int64Slicer) { 55 | s.slice = append(s.slice, value.AsSlice()...) 56 | } 57 | 58 | // Filter the slice based on the given function 59 | func (s *Int64Slicer) Filter(fn func(int64) bool) *Int64Slicer { 60 | result := &Int64Slicer{} 61 | for _, elem := range s.slice { 62 | if fn(elem) { 63 | result.Add(elem) 64 | } 65 | } 66 | return result 67 | } 68 | 69 | // Each runs a function on every element of the slice 70 | func (s *Int64Slicer) Each(fn func(int64)) { 71 | for _, elem := range s.slice { 72 | fn(elem) 73 | } 74 | } 75 | 76 | // Contains indicates if the given value is in the slice 77 | func (s *Int64Slicer) Contains(matcher int64) bool { 78 | result := false 79 | for _, elem := range s.slice { 80 | if elem == matcher { 81 | result = true 82 | } 83 | } 84 | return result 85 | } 86 | 87 | // Length returns the number of elements in the slice 88 | func (s *Int64Slicer) Length() int { 89 | return len(s.slice) 90 | } 91 | 92 | // Clear all elements in the slice 93 | func (s *Int64Slicer) Clear() { 94 | s.slice = []int64{} 95 | } 96 | 97 | // Deduplicate removes duplicate values from the slice 98 | func (s *Int64Slicer) Deduplicate() { 99 | 100 | result := &Int64Slicer{} 101 | 102 | for _, elem := range s.slice { 103 | if !result.Contains(elem) { 104 | result.Add(elem) 105 | } 106 | } 107 | 108 | s.slice = result.AsSlice() 109 | } 110 | 111 | // Join returns a string with the slicer elements separated by the given separator 112 | func (s *Int64Slicer) Join(separator string) string { 113 | var builder strings.Builder 114 | 115 | // Shortcut no elements 116 | if len(s.slice) == 0 { 117 | return "" 118 | } 119 | 120 | // Iterate over length - 1 121 | index := 0 122 | for index = 0; index < len(s.slice)-1; index++ { 123 | builder.WriteString(fmt.Sprintf("%v%s", s.slice[index], separator)) 124 | } 125 | builder.WriteString(fmt.Sprintf("%v", s.slice[index])) 126 | result := builder.String() 127 | return result 128 | } 129 | 130 | // Sort the slice values 131 | func (s *Int64Slicer) Sort() { 132 | sort.Slice(s.slice, func(i, j int) bool { return s.slice[i] < s.slice[j] }) 133 | } 134 | -------------------------------------------------------------------------------- /int64_test.go: -------------------------------------------------------------------------------- 1 | package slicer 2 | 3 | import ( 4 | "encoding/json" 5 | "testing" 6 | ) 7 | 8 | func TestInt64Add(t *testing.T) { 9 | 10 | s := Int64() 11 | s.Add(1) 12 | s.Add(2) 13 | 14 | expected := "[1,2]" 15 | actual, _ := json.Marshal(s.AsSlice()) 16 | if expected != string(actual) { 17 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 18 | } 19 | s.Clear() 20 | s.Add(1, 2) 21 | 22 | expected = "[1,2]" 23 | actual, _ = json.Marshal(s.AsSlice()) 24 | if expected != string(actual) { 25 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 26 | } 27 | } 28 | func TestInt64AddUnique(t *testing.T) { 29 | 30 | s := Int64() 31 | s.AddUnique(1) 32 | s.AddUnique(2) 33 | s.AddUnique(2) 34 | s.AddUnique(2) 35 | 36 | expected := "[1,2]" 37 | actual, _ := json.Marshal(s.AsSlice()) 38 | if expected != string(actual) { 39 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 40 | } 41 | 42 | s.Clear() 43 | s.AddUnique(1, 2, 1, 2, 2, 1) 44 | 45 | expected = "[1,2]" 46 | actual, _ = json.Marshal(s.AsSlice()) 47 | if expected != string(actual) { 48 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 49 | } 50 | } 51 | 52 | func TestInt64AddSlice(t *testing.T) { 53 | 54 | s := Int64() 55 | s.Add(1) 56 | s.Add(2) 57 | 58 | extras := []int64{3, 4} 59 | 60 | s.AddSlice(extras) 61 | 62 | expected := "[1,2,3,4]" 63 | actual, _ := json.Marshal(s.AsSlice()) 64 | if expected != string(actual) { 65 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 66 | } 67 | } 68 | 69 | func TestInt64AddSlicer(t *testing.T) { 70 | 71 | s := Int64() 72 | s.Add(1) 73 | s.Add(2) 74 | 75 | p := Int64() 76 | p.Add(3) 77 | p.Add(4) 78 | 79 | s.AddSlicer(p) 80 | 81 | expected := "[1,2,3,4]" 82 | actual, _ := json.Marshal(s.AsSlice()) 83 | if expected != string(actual) { 84 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 85 | } 86 | } 87 | 88 | func TestInt64Filter(t *testing.T) { 89 | 90 | s := Int64() 91 | s.Add(18) 92 | s.Add(180) 93 | s.Add(1) 94 | s.Add(10) 95 | s.Add(20) 96 | s.Add(3) 97 | s.Add(29) 98 | 99 | result := s.Filter(func(i int64) bool { 100 | return i > 19 101 | }) 102 | 103 | expected := "[180,20,29]" 104 | actual, _ := json.Marshal(result.AsSlice()) 105 | if expected != string(actual) { 106 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 107 | } 108 | } 109 | 110 | func TestInt64Each(t *testing.T) { 111 | 112 | s := Int64() 113 | s.Add(18) 114 | s.Add(10) 115 | s.Add(1) 116 | s.Add(10) 117 | s.Add(20) 118 | s.Add(3) 119 | s.Add(29) 120 | 121 | var result int64 122 | 123 | s.Each(func(i int64) { 124 | result = result + i 125 | }) 126 | 127 | var expected int64 = 91 128 | if expected != result { 129 | t.Errorf("Expected '%d', but got '%d'", expected, result) 130 | } 131 | } 132 | 133 | // TestOptionalInt64Slice tests when you construct a Int64 with 134 | // an existing slice 135 | func TestOptionalInt64Slice(t *testing.T) { 136 | data := []int64{1, 2, 3} 137 | s := Int64(data) 138 | 139 | var result int64 = 0 140 | s.Each(func(elem int64) { 141 | result += elem 142 | }) 143 | var expected int64 = 6 144 | if expected != result { 145 | t.Errorf("Expected '%d', but got '%d'", expected, result) 146 | } 147 | } 148 | 149 | // TestInt64Sort tests that the slicer can be sorted 150 | func TestInt64Sort(t *testing.T) { 151 | data := []int64{5, 4, 3, 2, 1} 152 | s := Int64(data) 153 | s.Sort() 154 | result := s.Join(",") 155 | expected := "1,2,3,4,5" 156 | if expected != result { 157 | t.Errorf("Expected '%s', but got '%s'", expected, result) 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /int8.go: -------------------------------------------------------------------------------- 1 | // Package slicer contains utility classes for handling slices 2 | package slicer 3 | 4 | // Imports 5 | import "sort" 6 | import "fmt" 7 | import "strings" 8 | 9 | // Int8Slicer handles slices of int8 10 | type Int8Slicer struct { 11 | slice []int8 12 | } 13 | 14 | // Int8 creates a new Int8Slicer 15 | func Int8(slice ...[]int8) *Int8Slicer { 16 | if len(slice) > 0 { 17 | return &Int8Slicer{slice: slice[0]} 18 | } 19 | return &Int8Slicer{} 20 | } 21 | 22 | // Add a int8 value to the slicer 23 | func (s *Int8Slicer) Add(value int8, additional ...int8) { 24 | s.slice = append(s.slice, value) 25 | s.slice = append(s.slice, additional...) 26 | } 27 | 28 | // AddUnique adds a int8 value to the slicer if it does not already exist 29 | func (s *Int8Slicer) AddUnique(value int8, additional ...int8) { 30 | 31 | if !s.Contains(value) { 32 | s.slice = append(s.slice, value) 33 | } 34 | 35 | // Add additional values 36 | for _, value := range additional { 37 | if !s.Contains(value) { 38 | s.slice = append(s.slice, value) 39 | } 40 | } 41 | } 42 | 43 | // AddSlice adds a int8 slice to the slicer 44 | func (s *Int8Slicer) AddSlice(value []int8) { 45 | s.slice = append(s.slice, value...) 46 | } 47 | 48 | // AsSlice returns the slice 49 | func (s *Int8Slicer) AsSlice() []int8 { 50 | return s.slice 51 | } 52 | 53 | // AddSlicer appends a Int8Slicer to the slicer 54 | func (s *Int8Slicer) AddSlicer(value *Int8Slicer) { 55 | s.slice = append(s.slice, value.AsSlice()...) 56 | } 57 | 58 | // Filter the slice based on the given function 59 | func (s *Int8Slicer) Filter(fn func(int8) bool) *Int8Slicer { 60 | result := &Int8Slicer{} 61 | for _, elem := range s.slice { 62 | if fn(elem) { 63 | result.Add(elem) 64 | } 65 | } 66 | return result 67 | } 68 | 69 | // Each runs a function on every element of the slice 70 | func (s *Int8Slicer) Each(fn func(int8)) { 71 | for _, elem := range s.slice { 72 | fn(elem) 73 | } 74 | } 75 | 76 | // Contains indicates if the given value is in the slice 77 | func (s *Int8Slicer) Contains(matcher int8) bool { 78 | result := false 79 | for _, elem := range s.slice { 80 | if elem == matcher { 81 | result = true 82 | } 83 | } 84 | return result 85 | } 86 | 87 | // Length returns the number of elements in the slice 88 | func (s *Int8Slicer) Length() int { 89 | return len(s.slice) 90 | } 91 | 92 | // Clear all elements in the slice 93 | func (s *Int8Slicer) Clear() { 94 | s.slice = []int8{} 95 | } 96 | 97 | // Deduplicate removes duplicate values from the slice 98 | func (s *Int8Slicer) Deduplicate() { 99 | 100 | result := &Int8Slicer{} 101 | 102 | for _, elem := range s.slice { 103 | if !result.Contains(elem) { 104 | result.Add(elem) 105 | } 106 | } 107 | 108 | s.slice = result.AsSlice() 109 | } 110 | 111 | // Join returns a string with the slicer elements separated by the given separator 112 | func (s *Int8Slicer) Join(separator string) string { 113 | var builder strings.Builder 114 | 115 | // Shortcut no elements 116 | if len(s.slice) == 0 { 117 | return "" 118 | } 119 | 120 | // Iterate over length - 1 121 | index := 0 122 | for index = 0; index < len(s.slice)-1; index++ { 123 | builder.WriteString(fmt.Sprintf("%v%s", s.slice[index], separator)) 124 | } 125 | builder.WriteString(fmt.Sprintf("%v", s.slice[index])) 126 | result := builder.String() 127 | return result 128 | } 129 | 130 | // Sort the slice values 131 | func (s *Int8Slicer) Sort() { 132 | sort.Slice(s.slice, func(i, j int) bool { return s.slice[i] < s.slice[j] }) 133 | } 134 | -------------------------------------------------------------------------------- /int8_test.go: -------------------------------------------------------------------------------- 1 | package slicer 2 | 3 | import ( 4 | "encoding/json" 5 | "testing" 6 | ) 7 | 8 | func TestInt8Add(t *testing.T) { 9 | 10 | s := Int8() 11 | s.Add(1) 12 | s.Add(2) 13 | 14 | expected := "[1,2]" 15 | actual, _ := json.Marshal(s.AsSlice()) 16 | if expected != string(actual) { 17 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 18 | } 19 | s.Clear() 20 | s.Add(1, 2) 21 | 22 | expected = "[1,2]" 23 | actual, _ = json.Marshal(s.AsSlice()) 24 | if expected != string(actual) { 25 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 26 | } 27 | } 28 | func TestInt8AddUnique(t *testing.T) { 29 | 30 | s := Int8() 31 | s.AddUnique(1) 32 | s.AddUnique(2) 33 | s.AddUnique(2) 34 | s.AddUnique(2) 35 | 36 | expected := "[1,2]" 37 | actual, _ := json.Marshal(s.AsSlice()) 38 | if expected != string(actual) { 39 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 40 | } 41 | 42 | s.Clear() 43 | s.AddUnique(1, 2, 1, 2, 2, 1) 44 | 45 | expected = "[1,2]" 46 | actual, _ = json.Marshal(s.AsSlice()) 47 | if expected != string(actual) { 48 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 49 | } 50 | } 51 | func TestInt8AddSlice(t *testing.T) { 52 | 53 | s := Int8() 54 | s.Add(1) 55 | s.Add(2) 56 | 57 | extras := []int8{3, 4} 58 | 59 | s.AddSlice(extras) 60 | 61 | expected := "[1,2,3,4]" 62 | actual, _ := json.Marshal(s.AsSlice()) 63 | if expected != string(actual) { 64 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 65 | } 66 | } 67 | 68 | func TestInt8AddSlicer(t *testing.T) { 69 | 70 | s := Int8() 71 | s.Add(1) 72 | s.Add(2) 73 | 74 | p := Int8() 75 | p.Add(3) 76 | p.Add(4) 77 | 78 | s.AddSlicer(p) 79 | 80 | expected := "[1,2,3,4]" 81 | actual, _ := json.Marshal(s.AsSlice()) 82 | if expected != string(actual) { 83 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 84 | } 85 | } 86 | func TestInt8Filter(t *testing.T) { 87 | 88 | s := Int8() 89 | s.Add(18) 90 | s.Add(120) 91 | s.Add(1) 92 | s.Add(10) 93 | s.Add(20) 94 | s.Add(3) 95 | s.Add(29) 96 | 97 | result := s.Filter(func(i int8) bool { 98 | return i > 19 99 | }) 100 | 101 | expected := "[120,20,29]" 102 | actual, _ := json.Marshal(result.AsSlice()) 103 | if expected != string(actual) { 104 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 105 | } 106 | } 107 | 108 | func TestInt8Each(t *testing.T) { 109 | 110 | s := Int8() 111 | s.Add(18) 112 | s.Add(10) 113 | s.Add(1) 114 | s.Add(10) 115 | s.Add(20) 116 | s.Add(3) 117 | s.Add(29) 118 | 119 | var result int8 120 | 121 | s.Each(func(i int8) { 122 | result = result + i 123 | }) 124 | 125 | var expected int8 = 91 126 | if expected != result { 127 | t.Errorf("Expected '%d', but got '%d'", expected, result) 128 | } 129 | } 130 | 131 | // TestOptionalInt8Slice tests when you construct a Int8 with 132 | // an existing slice 133 | func TestOptionalInt8Slice(t *testing.T) { 134 | data := []int8{1, 2, 3} 135 | s := Int8(data) 136 | 137 | var result int8 = 0 138 | s.Each(func(elem int8) { 139 | result += elem 140 | }) 141 | var expected int8 = 6 142 | if expected != result { 143 | t.Errorf("Expected '%d', but got '%d'", expected, result) 144 | } 145 | } 146 | 147 | // TestInt8Sort tests that the slicer can be sorted 148 | func TestInt8Sort(t *testing.T) { 149 | data := []int8{5, 4, 3, 2, 1} 150 | s := Int8(data) 151 | s.Sort() 152 | result := s.Join(",") 153 | expected := "1,2,3,4,5" 154 | if expected != result { 155 | t.Errorf("Expected '%s', but got '%s'", expected, result) 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /int_test.go: -------------------------------------------------------------------------------- 1 | package slicer 2 | 3 | import ( 4 | "encoding/json" 5 | "testing" 6 | ) 7 | 8 | func TestIntAdd(t *testing.T) { 9 | 10 | s := Int() 11 | s.Add(1) 12 | s.Add(2) 13 | 14 | expected := "[1,2]" 15 | actual, _ := json.Marshal(s.AsSlice()) 16 | if expected != string(actual) { 17 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 18 | } 19 | 20 | s.Clear() 21 | s.Add(1, 2) 22 | 23 | expected = "[1,2]" 24 | actual, _ = json.Marshal(s.AsSlice()) 25 | if expected != string(actual) { 26 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 27 | } 28 | } 29 | 30 | func TestIntAddUnique(t *testing.T) { 31 | 32 | s := Int() 33 | s.AddUnique(1) 34 | s.AddUnique(2) 35 | s.AddUnique(2) 36 | s.AddUnique(2) 37 | 38 | expected := "[1,2]" 39 | actual, _ := json.Marshal(s.AsSlice()) 40 | if expected != string(actual) { 41 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 42 | } 43 | 44 | s.Clear() 45 | s.AddUnique(1, 2, 1, 2, 2, 1) 46 | 47 | expected = "[1,2]" 48 | actual, _ = json.Marshal(s.AsSlice()) 49 | if expected != string(actual) { 50 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 51 | } 52 | } 53 | 54 | func TestIntAddSlice(t *testing.T) { 55 | 56 | s := Int() 57 | s.Add(1) 58 | s.Add(2) 59 | 60 | extras := []int{3, 4} 61 | 62 | s.AddSlice(extras) 63 | 64 | expected := "[1,2,3,4]" 65 | actual, _ := json.Marshal(s.AsSlice()) 66 | if expected != string(actual) { 67 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 68 | } 69 | } 70 | 71 | func TestIntAddSlicer(t *testing.T) { 72 | 73 | s := Int() 74 | s.Add(1) 75 | s.Add(2) 76 | 77 | p := Int() 78 | p.Add(3) 79 | p.Add(4) 80 | 81 | s.AddSlicer(p) 82 | 83 | expected := "[1,2,3,4]" 84 | actual, _ := json.Marshal(s.AsSlice()) 85 | if expected != string(actual) { 86 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 87 | } 88 | } 89 | 90 | func TestIntFilter(t *testing.T) { 91 | 92 | s := Int() 93 | s.Add(18) 94 | s.Add(120) 95 | s.Add(1) 96 | s.Add(10) 97 | s.Add(20) 98 | s.Add(3) 99 | s.Add(29) 100 | 101 | result := s.Filter(func(i int) bool { 102 | return i > 19 103 | }) 104 | 105 | expected := "[120,20,29]" 106 | actual, _ := json.Marshal(result.AsSlice()) 107 | if expected != string(actual) { 108 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 109 | } 110 | } 111 | 112 | // TestOptionalIntSlice tests when you construct a Int with 113 | // an existing slice 114 | func TestOptionalIntSlice(t *testing.T) { 115 | data := []int{1, 2, 3} 116 | s := Int(data) 117 | 118 | var result = 0 119 | s.Each(func(elem int) { 120 | result += elem 121 | }) 122 | var expected = 6 123 | if expected != result { 124 | t.Errorf("Expected '%d', but got '%d'", expected, result) 125 | } 126 | } 127 | 128 | // TestIntSort tests that the slicer can be sorted 129 | func TestIntSort(t *testing.T) { 130 | data := []int{5, 4, 3, 2, 1} 131 | s := Int(data) 132 | s.Sort() 133 | result := s.Join(",") 134 | expected := "1,2,3,4,5" 135 | if expected != result { 136 | t.Errorf("Expected '%s', but got '%s'", expected, result) 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /interface.go: -------------------------------------------------------------------------------- 1 | // Package slicer contains utility classes for handling slices 2 | package slicer 3 | 4 | // Imports 5 | import "fmt" 6 | import "strings" 7 | 8 | // InterfaceSlicer handles slices of interface{} 9 | type InterfaceSlicer struct { 10 | slice []interface{} 11 | } 12 | 13 | // Interface creates a new InterfaceSlicer 14 | func Interface(slice ...[]interface{}) *InterfaceSlicer { 15 | if len(slice) > 0 { 16 | return &InterfaceSlicer{slice: slice[0]} 17 | } 18 | return &InterfaceSlicer{} 19 | } 20 | 21 | // Add a interface{} value to the slicer 22 | func (s *InterfaceSlicer) Add(value interface{}, additional ...interface{}) { 23 | s.slice = append(s.slice, value) 24 | s.slice = append(s.slice, additional...) 25 | } 26 | 27 | // AddUnique adds a interface{} value to the slicer if it does not already exist 28 | func (s *InterfaceSlicer) AddUnique(value interface{}, additional ...interface{}) { 29 | 30 | if !s.Contains(value) { 31 | s.slice = append(s.slice, value) 32 | } 33 | 34 | // Add additional values 35 | for _, value := range additional { 36 | if !s.Contains(value) { 37 | s.slice = append(s.slice, value) 38 | } 39 | } 40 | } 41 | 42 | // AddSlice adds a interface{} slice to the slicer 43 | func (s *InterfaceSlicer) AddSlice(value []interface{}) { 44 | s.slice = append(s.slice, value...) 45 | } 46 | 47 | // AsSlice returns the slice 48 | func (s *InterfaceSlicer) AsSlice() []interface{} { 49 | return s.slice 50 | } 51 | 52 | // AddSlicer appends a InterfaceSlicer to the slicer 53 | func (s *InterfaceSlicer) AddSlicer(value *InterfaceSlicer) { 54 | s.slice = append(s.slice, value.AsSlice()...) 55 | } 56 | 57 | // Filter the slice based on the given function 58 | func (s *InterfaceSlicer) Filter(fn func(interface{}) bool) *InterfaceSlicer { 59 | result := &InterfaceSlicer{} 60 | for _, elem := range s.slice { 61 | if fn(elem) { 62 | result.Add(elem) 63 | } 64 | } 65 | return result 66 | } 67 | 68 | // Each runs a function on every element of the slice 69 | func (s *InterfaceSlicer) Each(fn func(interface{})) { 70 | for _, elem := range s.slice { 71 | fn(elem) 72 | } 73 | } 74 | 75 | // Contains indicates if the given value is in the slice 76 | func (s *InterfaceSlicer) Contains(matcher interface{}) bool { 77 | result := false 78 | for _, elem := range s.slice { 79 | if elem == matcher { 80 | result = true 81 | } 82 | } 83 | return result 84 | } 85 | 86 | // Length returns the number of elements in the slice 87 | func (s *InterfaceSlicer) Length() int { 88 | return len(s.slice) 89 | } 90 | 91 | // Clear all elements in the slice 92 | func (s *InterfaceSlicer) Clear() { 93 | s.slice = []interface{}{} 94 | } 95 | 96 | // Deduplicate removes duplicate values from the slice 97 | func (s *InterfaceSlicer) Deduplicate() { 98 | 99 | result := &InterfaceSlicer{} 100 | 101 | for _, elem := range s.slice { 102 | if !result.Contains(elem) { 103 | result.Add(elem) 104 | } 105 | } 106 | 107 | s.slice = result.AsSlice() 108 | } 109 | 110 | // Join returns a string with the slicer elements separated by the given separator 111 | func (s *InterfaceSlicer) Join(separator string) string { 112 | var builder strings.Builder 113 | 114 | // Shortcut no elements 115 | if len(s.slice) == 0 { 116 | return "" 117 | } 118 | 119 | // Iterate over length - 1 120 | index := 0 121 | for index = 0; index < len(s.slice)-1; index++ { 122 | builder.WriteString(fmt.Sprintf("%v%s", s.slice[index], separator)) 123 | } 124 | builder.WriteString(fmt.Sprintf("%v", s.slice[index])) 125 | result := builder.String() 126 | return result 127 | } 128 | -------------------------------------------------------------------------------- /interface_test.go: -------------------------------------------------------------------------------- 1 | package slicer 2 | 3 | import ( 4 | "encoding/json" 5 | "testing" 6 | ) 7 | 8 | func TestInterfaceAdd(t *testing.T) { 9 | 10 | s := Interface() 11 | var a interface{} = 1 12 | var b interface{} = "hello" 13 | s.Add(a) 14 | s.Add(b) 15 | 16 | expected := `[1,"hello"]` 17 | actual, _ := json.Marshal(s.AsSlice()) 18 | if expected != string(actual) { 19 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 20 | } 21 | 22 | // Add more than one value 23 | s.Clear() 24 | s.Add(a, b) 25 | expected = `[1,"hello"]` 26 | actual, _ = json.Marshal(s.AsSlice()) 27 | if expected != string(actual) { 28 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 29 | } 30 | } 31 | 32 | func TestInterfaceAddUnique(t *testing.T) { 33 | 34 | s := Interface() 35 | var a interface{} = 1 36 | var b interface{} = "hello" 37 | s.AddUnique(a) 38 | s.AddUnique(a) 39 | s.AddUnique(b) 40 | 41 | expected := `[1,"hello"]` 42 | actual, _ := json.Marshal(s.AsSlice()) 43 | if expected != string(actual) { 44 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 45 | } 46 | 47 | // AddUnique more than one value 48 | s.Clear() 49 | s.AddUnique(a, b, b, a) 50 | expected = `[1,"hello"]` 51 | actual, _ = json.Marshal(s.AsSlice()) 52 | if expected != string(actual) { 53 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 54 | } 55 | } 56 | 57 | func TestInterfaceAddSlice(t *testing.T) { 58 | 59 | s := Interface() 60 | var a interface{} = 1 61 | var b interface{} = "hello" 62 | s.Add(a) 63 | s.Add(b) 64 | 65 | extras := []interface{}{true, 6.6} 66 | 67 | s.AddSlice(extras) 68 | 69 | expected := `[1,"hello",true,6.6]` 70 | actual, _ := json.Marshal(s.AsSlice()) 71 | if expected != string(actual) { 72 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 73 | } 74 | } 75 | func TestInterfaceAddSlicer(t *testing.T) { 76 | 77 | s := Interface() 78 | var a interface{} = 1 79 | var b interface{} = "hello" 80 | s.Add(a) 81 | s.Add(b) 82 | 83 | p := Interface() 84 | var c interface{} = true 85 | var d interface{} = 6.6 86 | p.Add(c) 87 | p.Add(d) 88 | 89 | s.AddSlicer(p) 90 | 91 | expected := `[1,"hello",true,6.6]` 92 | actual, _ := json.Marshal(s.AsSlice()) 93 | if expected != string(actual) { 94 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 95 | } 96 | } 97 | 98 | func TestInterfaceFilter(t *testing.T) { 99 | 100 | s := Interface() 101 | s.Add(1) 102 | s.Add("hello") 103 | s.Add(true) 104 | s.Add("world") 105 | s.Add(9.9) 106 | 107 | result := s.Filter(func(i interface{}) bool { 108 | _, ok := i.(string) 109 | return ok 110 | }) 111 | 112 | expected := `["hello","world"]` 113 | actual, _ := json.Marshal(result.AsSlice()) 114 | if expected != string(actual) { 115 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 116 | } 117 | } 118 | 119 | func TestInterfaceEach(t *testing.T) { 120 | 121 | s := Interface() 122 | s.Add(1) 123 | s.Add("hello") 124 | s.Add(true) 125 | s.Add("world") 126 | s.Add(9.9) 127 | 128 | result := String() 129 | s.Each(func(i interface{}) { 130 | val, ok := i.(string) 131 | if ok { 132 | result.Add(val + "!") 133 | } 134 | }) 135 | 136 | expected := `["hello!","world!"]` 137 | actual, _ := json.Marshal(result.AsSlice()) 138 | if expected != string(actual) { 139 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 140 | } 141 | } 142 | 143 | // TestOptionalInterfaceSlice tests when you construct a Interface with 144 | // an existing slice 145 | func TestOptionalInterfaceSlice(t *testing.T) { 146 | data := []interface{}{"one", "two", "three"} 147 | s := Interface(data) 148 | 149 | result := "" 150 | s.Each(func(elem interface{}) { 151 | result += elem.(string) 152 | }) 153 | expected := "onetwothree" 154 | if expected != result { 155 | t.Errorf("Expected '%s', but got '%s'", expected, result) 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /join_test.go: -------------------------------------------------------------------------------- 1 | package slicer 2 | 3 | import "testing" 4 | 5 | func TestStringJoin(t *testing.T) { 6 | 7 | /* Test multiple elements */ 8 | data := []string{"cat", "bat", "dog", "arachnid"} 9 | s := String(data) 10 | 11 | // Positive test 12 | expected := "cat,bat,dog,arachnid" 13 | result := s.Join(",") 14 | if result != expected { 15 | t.Errorf("Expected '%s', but got '%s'", expected, result) 16 | } 17 | 18 | // Negative test 19 | expected = "cat,bat,dog,horse" 20 | result = s.Join(",") 21 | if result == expected { 22 | t.Errorf("Expected '%s', but got '%s'", expected, result) 23 | } 24 | /* Test single element */ 25 | s = String() 26 | s.Add("hello") 27 | 28 | // Positive test 29 | expected = "hello" 30 | result = s.Join(",") 31 | if result != expected { 32 | t.Errorf("Expected '%s', but got '%s'", expected, result) 33 | } 34 | 35 | // Negative test 36 | expected = "hello," 37 | result = s.Join(",") 38 | if result == expected { 39 | t.Errorf("Expected '%s', but got '%s'", expected, result) 40 | } 41 | 42 | /* Test no element */ 43 | s = String() 44 | expected = "" 45 | result = s.Join(",") 46 | if result != expected { 47 | t.Errorf("Expected '%s', but got '%s'", expected, result) 48 | } 49 | } 50 | 51 | func TestInterfaceJoin(t *testing.T) { 52 | 53 | /* Test multiple elements */ 54 | s := Interface() 55 | var a interface{} = 1 56 | var b interface{} = "hello" 57 | s.Add(a) 58 | s.Add(b) 59 | 60 | // Positive test 61 | expected := "1,hello" 62 | result := s.Join(",") 63 | if result != expected { 64 | t.Errorf("Expected '%s', but got '%s'", expected, result) 65 | } 66 | 67 | // Negative test 68 | expected = "1,hello," 69 | result = s.Join(",") 70 | if result == expected { 71 | t.Errorf("Expected '%s', but got '%s'", expected, result) 72 | } 73 | 74 | /* Test single element */ 75 | s = Interface() 76 | s.Add(a) 77 | 78 | // Positive test 79 | expected = "1" 80 | result = s.Join(",") 81 | if result != expected { 82 | t.Errorf("Expected '%s', but got '%s'", expected, result) 83 | } 84 | 85 | // Negative test 86 | expected = "1," 87 | result = s.Join(",") 88 | if result == expected { 89 | t.Errorf("Expected '%s', but got '%s'", expected, result) 90 | } 91 | 92 | /* Test no element */ 93 | s = Interface() 94 | expected = "" 95 | result = s.Join(",") 96 | if result != expected { 97 | t.Errorf("Expected '%s', but got '%s'", expected, result) 98 | } 99 | 100 | } 101 | 102 | func TestInt64Join(t *testing.T) { 103 | 104 | /* Test multiple elements */ 105 | 106 | data := []int64{1, 2, 3} 107 | s := Int64(data) 108 | 109 | // Positive test 110 | expected := "1,2,3" 111 | result := s.Join(",") 112 | if result != expected { 113 | t.Errorf("Expected '%s', but got '%s'", expected, result) 114 | } 115 | 116 | // Negative test 117 | expected = "1,2,3," 118 | result = s.Join(",") 119 | if result == expected { 120 | t.Errorf("Expected '%s', but got '%s'", expected, result) 121 | } 122 | 123 | /* Test single element */ 124 | s = Int64() 125 | s.Add(1) 126 | 127 | // Positive test 128 | expected = "1" 129 | result = s.Join(",") 130 | if result != expected { 131 | t.Errorf("Expected '%s', but got '%s'", expected, result) 132 | } 133 | 134 | // Negative test 135 | expected = "1," 136 | result = s.Join(",") 137 | if result == expected { 138 | t.Errorf("Expected '%s', but got '%s'", expected, result) 139 | } 140 | 141 | /* Test no element */ 142 | s = Int64() 143 | expected = "" 144 | result = s.Join(",") 145 | if result != expected { 146 | t.Errorf("Expected '%s', but got '%s'", expected, result) 147 | } 148 | } 149 | 150 | func TestInt32Join(t *testing.T) { 151 | 152 | /* Test multiple elements */ 153 | 154 | data := []int32{1, 2, 3} 155 | s := Int32(data) 156 | 157 | // Positive test 158 | expected := "1,2,3" 159 | result := s.Join(",") 160 | if result != expected { 161 | t.Errorf("Expected '%s', but got '%s'", expected, result) 162 | } 163 | 164 | // Negative test 165 | expected = "1,2,3," 166 | result = s.Join(",") 167 | if result == expected { 168 | t.Errorf("Expected '%s', but got '%s'", expected, result) 169 | } 170 | 171 | /* Test single element */ 172 | s = Int32() 173 | s.Add(1) 174 | 175 | // Positive test 176 | expected = "1" 177 | result = s.Join(",") 178 | if result != expected { 179 | t.Errorf("Expected '%s', but got '%s'", expected, result) 180 | } 181 | 182 | // Negative test 183 | expected = "1," 184 | result = s.Join(",") 185 | if result == expected { 186 | t.Errorf("Expected '%s', but got '%s'", expected, result) 187 | } 188 | 189 | /* Test no element */ 190 | s = Int32() 191 | expected = "" 192 | result = s.Join(",") 193 | if result != expected { 194 | t.Errorf("Expected '%s', but got '%s'", expected, result) 195 | } 196 | } 197 | 198 | func TestInt16Join(t *testing.T) { 199 | 200 | /* Test multiple elements */ 201 | 202 | data := []int16{1, 2, 3} 203 | s := Int16(data) 204 | 205 | // Positive test 206 | expected := "1,2,3" 207 | result := s.Join(",") 208 | if result != expected { 209 | t.Errorf("Expected '%s', but got '%s'", expected, result) 210 | } 211 | 212 | // Negative test 213 | expected = "1,2,3," 214 | result = s.Join(",") 215 | if result == expected { 216 | t.Errorf("Expected '%s', but got '%s'", expected, result) 217 | } 218 | 219 | /* Test single element */ 220 | s = Int16() 221 | s.Add(1) 222 | 223 | // Positive test 224 | expected = "1" 225 | result = s.Join(",") 226 | if result != expected { 227 | t.Errorf("Expected '%s', but got '%s'", expected, result) 228 | } 229 | 230 | // Negative test 231 | expected = "1," 232 | result = s.Join(",") 233 | if result == expected { 234 | t.Errorf("Expected '%s', but got '%s'", expected, result) 235 | } 236 | 237 | /* Test no element */ 238 | s = Int16() 239 | expected = "" 240 | result = s.Join(",") 241 | if result != expected { 242 | t.Errorf("Expected '%s', but got '%s'", expected, result) 243 | } 244 | } 245 | 246 | func TestInt8Join(t *testing.T) { 247 | 248 | /* Test multiple elements */ 249 | 250 | data := []int8{1, 2, 3} 251 | s := Int8(data) 252 | 253 | // Positive test 254 | expected := "1,2,3" 255 | result := s.Join(",") 256 | if result != expected { 257 | t.Errorf("Expected '%s', but got '%s'", expected, result) 258 | } 259 | 260 | // Negative test 261 | expected = "1,2,3," 262 | result = s.Join(",") 263 | if result == expected { 264 | t.Errorf("Expected '%s', but got '%s'", expected, result) 265 | } 266 | 267 | /* Test single element */ 268 | s = Int8() 269 | s.Add(1) 270 | 271 | // Positive test 272 | expected = "1" 273 | result = s.Join(",") 274 | if result != expected { 275 | t.Errorf("Expected '%s', but got '%s'", expected, result) 276 | } 277 | 278 | // Negative test 279 | expected = "1," 280 | result = s.Join(",") 281 | if result == expected { 282 | t.Errorf("Expected '%s', but got '%s'", expected, result) 283 | } 284 | 285 | /* Test no element */ 286 | s = Int8() 287 | expected = "" 288 | result = s.Join(",") 289 | if result != expected { 290 | t.Errorf("Expected '%s', but got '%s'", expected, result) 291 | } 292 | } 293 | 294 | func TestIntJoin(t *testing.T) { 295 | 296 | /* Test multiple elements */ 297 | 298 | data := []int{1, 2, 3} 299 | s := Int(data) 300 | 301 | // Positive test 302 | expected := "1,2,3" 303 | result := s.Join(",") 304 | if result != expected { 305 | t.Errorf("Expected '%s', but got '%s'", expected, result) 306 | } 307 | 308 | // Negative test 309 | expected = "1,2,3," 310 | result = s.Join(",") 311 | if result == expected { 312 | t.Errorf("Expected '%s', but got '%s'", expected, result) 313 | } 314 | 315 | /* Test single element */ 316 | s = Int() 317 | s.Add(1) 318 | 319 | // Positive test 320 | expected = "1" 321 | result = s.Join(",") 322 | if result != expected { 323 | t.Errorf("Expected '%s', but got '%s'", expected, result) 324 | } 325 | 326 | // Negative test 327 | expected = "1," 328 | result = s.Join(",") 329 | if result == expected { 330 | t.Errorf("Expected '%s', but got '%s'", expected, result) 331 | } 332 | 333 | /* Test no element */ 334 | s = Int() 335 | expected = "" 336 | result = s.Join(",") 337 | if result != expected { 338 | t.Errorf("Expected '%s', but got '%s'", expected, result) 339 | } 340 | } 341 | 342 | func TestBoolJoin(t *testing.T) { 343 | 344 | /* Test multpile elements */ 345 | data := []bool{true, false, true} 346 | s := Bool(data) 347 | 348 | // Positive test 349 | expected := "true,false,true" 350 | result := s.Join(",") 351 | if result != expected { 352 | t.Errorf("Expected '%s', but got '%s'", expected, result) 353 | } 354 | 355 | // Negative test 356 | expected = "true,false,true," 357 | result = s.Join(",") 358 | if result == expected { 359 | t.Errorf("Expected '%s', but got '%s'", expected, result) 360 | } 361 | /* Test single element */ 362 | s = Bool() 363 | s.Add(false) 364 | 365 | // Positive test 366 | expected = "false" 367 | result = s.Join(",") 368 | if result != expected { 369 | t.Errorf("Expected '%s', but got '%s'", expected, result) 370 | } 371 | 372 | // Negative test 373 | expected = "false," 374 | result = s.Join(",") 375 | if result == expected { 376 | t.Errorf("Expected '%s', but got '%s'", expected, result) 377 | } 378 | 379 | /* Test no element */ 380 | s = Bool() 381 | expected = "" 382 | result = s.Join(",") 383 | if result != expected { 384 | t.Errorf("Expected '%s', but got '%s'", expected, result) 385 | } 386 | } 387 | 388 | func TestFloat64Join(t *testing.T) { 389 | 390 | data := []float64{1.4, 2.1, 3} 391 | s := Float64(data) 392 | 393 | // Positive test 394 | expected := "1.4,2.1,3" 395 | result := s.Join(",") 396 | if result != expected { 397 | t.Errorf("Expected '%s', but got '%s'", expected, result) 398 | } 399 | 400 | // Negative test 401 | expected = "1.4,2.1,3," 402 | result = s.Join(",") 403 | if result == expected { 404 | t.Errorf("Expected '%s', but got '%s'", expected, result) 405 | } 406 | /* Test single element */ 407 | s = Float64() 408 | s.Add(1.982) 409 | 410 | // Positive test 411 | expected = "1.982" 412 | result = s.Join(",") 413 | if result != expected { 414 | t.Errorf("Expected '%s', but got '%s'", expected, result) 415 | } 416 | 417 | // Negative test 418 | expected = "1.982," 419 | result = s.Join(",") 420 | if result == expected { 421 | t.Errorf("Expected '%s', but got '%s'", expected, result) 422 | } 423 | 424 | /* Test no element */ 425 | s = Float64() 426 | expected = "" 427 | result = s.Join(",") 428 | if result != expected { 429 | t.Errorf("Expected '%s', but got '%s'", expected, result) 430 | } 431 | } 432 | func TestFloat32Join(t *testing.T) { 433 | 434 | data := []float32{1.4, 2.1, 3} 435 | s := Float32(data) 436 | 437 | // Positive test 438 | expected := "1.4,2.1,3" 439 | result := s.Join(",") 440 | if result != expected { 441 | t.Errorf("Expected '%s', but got '%s'", expected, result) 442 | } 443 | 444 | // Negative test 445 | expected = "1.4,2.1,3," 446 | result = s.Join(",") 447 | if result == expected { 448 | t.Errorf("Expected '%s', but got '%s'", expected, result) 449 | } 450 | 451 | /* Test single element */ 452 | s = Float32() 453 | s.Add(1.982) 454 | 455 | // Positive test 456 | expected = "1.982" 457 | result = s.Join(",") 458 | if result != expected { 459 | t.Errorf("Expected '%s', but got '%s'", expected, result) 460 | } 461 | 462 | // Negative test 463 | expected = "1.982," 464 | result = s.Join(",") 465 | if result == expected { 466 | t.Errorf("Expected '%s', but got '%s'", expected, result) 467 | } 468 | 469 | /* Test no element */ 470 | s = Float32() 471 | expected = "" 472 | result = s.Join(",") 473 | if result != expected { 474 | t.Errorf("Expected '%s', but got '%s'", expected, result) 475 | } 476 | } 477 | -------------------------------------------------------------------------------- /length_test.go: -------------------------------------------------------------------------------- 1 | package slicer 2 | 3 | import "testing" 4 | 5 | func TestStringLength(t *testing.T) { 6 | 7 | /* Test multiple elements */ 8 | data := []string{"cat", "bat", "dog", "arachnid"} 9 | s := String(data) 10 | 11 | // Positive test 12 | expected := 4 13 | result := s.Length() 14 | if result != expected { 15 | t.Errorf("Expected '%d', but got '%d'", expected, result) 16 | } 17 | 18 | // Negative test 19 | expected = 3 20 | result = s.Length() 21 | if result == expected { 22 | t.Errorf("Expected '%d', but got '%d'", expected, result) 23 | } 24 | 25 | /* Test no element */ 26 | s = String() 27 | expected = 0 28 | result = s.Length() 29 | if result != expected { 30 | t.Errorf("Expected '%d', but got '%d'", expected, result) 31 | } 32 | } 33 | 34 | func TestInterfaceLength(t *testing.T) { 35 | 36 | /* Test multiple elements */ 37 | s := Interface() 38 | var a interface{} = 1 39 | var b interface{} = "hello" 40 | s.Add(a) 41 | s.Add(b) 42 | 43 | // Positive test 44 | expected := 2 45 | result := s.Length() 46 | if result != expected { 47 | t.Errorf("Expected '%d', but got '%d'", expected, result) 48 | } 49 | 50 | // Negative test 51 | expected = 3 52 | result = s.Length() 53 | if result == expected { 54 | t.Errorf("Expected '%d', but got '%d'", expected, result) 55 | } 56 | 57 | /* Test no element */ 58 | s = Interface() 59 | expected = 0 60 | result = s.Length() 61 | if result != expected { 62 | t.Errorf("Expected '%d', but got '%d'", expected, result) 63 | } 64 | 65 | } 66 | 67 | func TestInt64Length(t *testing.T) { 68 | 69 | /* Test multiple elements */ 70 | 71 | data := []int64{1, 2, 3} 72 | s := Int64(data) 73 | 74 | // Positive test 75 | expected := 3 76 | result := s.Length() 77 | if result != expected { 78 | t.Errorf("Expected '%d', but got '%d'", expected, result) 79 | } 80 | 81 | // Negative test 82 | expected = 2 83 | result = s.Length() 84 | if result == expected { 85 | t.Errorf("Expected '%d', but got '%d'", expected, result) 86 | } 87 | 88 | /* Test no element */ 89 | s = Int64() 90 | expected = 0 91 | result = s.Length() 92 | if result != expected { 93 | t.Errorf("Expected '%d', but got '%d'", expected, result) 94 | } 95 | } 96 | 97 | func TestInt32Length(t *testing.T) { 98 | 99 | /* Test multiple elements */ 100 | 101 | data := []int32{1, 2, 3} 102 | s := Int32(data) 103 | 104 | // Positive test 105 | expected := 3 106 | result := s.Length() 107 | if result != expected { 108 | t.Errorf("Expected '%d', but got '%d'", expected, result) 109 | } 110 | 111 | // Negative test 112 | expected = 2 113 | result = s.Length() 114 | if result == expected { 115 | t.Errorf("Expected '%d', but got '%d'", expected, result) 116 | } 117 | 118 | /* Test no element */ 119 | s = Int32() 120 | expected = 0 121 | result = s.Length() 122 | if result != expected { 123 | t.Errorf("Expected '%d', but got '%d'", expected, result) 124 | } 125 | } 126 | 127 | func TestInt16Length(t *testing.T) { 128 | 129 | /* Test multiple elements */ 130 | 131 | data := []int16{1, 2, 3} 132 | s := Int16(data) 133 | 134 | // Positive test 135 | expected := 3 136 | result := s.Length() 137 | if result != expected { 138 | t.Errorf("Expected '%d', but got '%d'", expected, result) 139 | } 140 | 141 | // Negative test 142 | expected = 2 143 | result = s.Length() 144 | if result == expected { 145 | t.Errorf("Expected '%d', but got '%d'", expected, result) 146 | } 147 | 148 | /* Test no element */ 149 | s = Int16() 150 | expected = 0 151 | result = s.Length() 152 | if result != expected { 153 | t.Errorf("Expected '%d', but got '%d'", expected, result) 154 | } 155 | } 156 | 157 | func TestInt8Length(t *testing.T) { 158 | 159 | /* Test multiple elements */ 160 | 161 | data := []int8{1, 2, 3} 162 | s := Int8(data) 163 | 164 | // Positive test 165 | expected := 3 166 | result := s.Length() 167 | if result != expected { 168 | t.Errorf("Expected '%d', but got '%d'", expected, result) 169 | } 170 | 171 | // Negative test 172 | expected = 2 173 | result = s.Length() 174 | if result == expected { 175 | t.Errorf("Expected '%d', but got '%d'", expected, result) 176 | } 177 | 178 | /* Test no element */ 179 | s = Int8() 180 | expected = 0 181 | result = s.Length() 182 | if result != expected { 183 | t.Errorf("Expected '%d', but got '%d'", expected, result) 184 | } 185 | } 186 | 187 | func TestIntLength(t *testing.T) { 188 | 189 | /* Test multiple elements */ 190 | 191 | data := []int{1, 2, 3} 192 | s := Int(data) 193 | 194 | // Positive test 195 | expected := 3 196 | result := s.Length() 197 | if result != expected { 198 | t.Errorf("Expected '%d', but got '%d'", expected, result) 199 | } 200 | 201 | // Negative test 202 | expected = 2 203 | result = s.Length() 204 | if result == expected { 205 | t.Errorf("Expected '%d', but got '%d'", expected, result) 206 | } 207 | 208 | /* Test no element */ 209 | s = Int() 210 | expected = 0 211 | result = s.Length() 212 | if result != expected { 213 | t.Errorf("Expected '%d', but got '%d'", expected, result) 214 | } 215 | } 216 | 217 | func TestBoolLength(t *testing.T) { 218 | 219 | /* Test multpile elements */ 220 | data := []bool{true, false, true} 221 | s := Bool(data) 222 | 223 | // Positive test 224 | expected := 3 225 | result := s.Length() 226 | if result != expected { 227 | t.Errorf("Expected '%d', but got '%d'", expected, result) 228 | } 229 | 230 | // Negative test 231 | expected = 2 232 | result = s.Length() 233 | if result == expected { 234 | t.Errorf("Expected '%d', but got '%d'", expected, result) 235 | } 236 | 237 | /* Test no element */ 238 | s = Bool() 239 | expected = 0 240 | result = s.Length() 241 | if result != expected { 242 | t.Errorf("Expected '%d', but got '%d'", expected, result) 243 | } 244 | } 245 | 246 | func TestFloat64Length(t *testing.T) { 247 | 248 | data := []float64{1.4, 2.1, 3} 249 | s := Float64(data) 250 | 251 | // Positive test 252 | expected := 3 253 | result := s.Length() 254 | if result != expected { 255 | t.Errorf("Expected '%d', but got '%d'", expected, result) 256 | } 257 | 258 | // Negative test 259 | expected = 2 260 | result = s.Length() 261 | if result == expected { 262 | t.Errorf("Expected '%d', but got '%d'", expected, result) 263 | } 264 | 265 | /* Test no element */ 266 | s = Float64() 267 | expected = 0 268 | result = s.Length() 269 | if result != expected { 270 | t.Errorf("Expected '%d', but got '%d'", expected, result) 271 | } 272 | } 273 | func TestFloat32Length(t *testing.T) { 274 | 275 | data := []float32{1.4, 2.1, 3} 276 | s := Float32(data) 277 | 278 | // Positive test 279 | expected := 3 280 | result := s.Length() 281 | if result != expected { 282 | t.Errorf("Expected '%d', but got '%d'", expected, result) 283 | } 284 | 285 | // Negative test 286 | expected = 2 287 | result = s.Length() 288 | if result == expected { 289 | t.Errorf("Expected '%d', but got '%d'", expected, result) 290 | } 291 | 292 | /* Test no element */ 293 | s = Float32() 294 | expected = 0 295 | result = s.Length() 296 | if result != expected { 297 | t.Errorf("Expected '%d', but got '%d'", expected, result) 298 | } 299 | } 300 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leaanthony/slicer/33c619aa00508e2307b8ed4038d202e200240476/logo.png -------------------------------------------------------------------------------- /scripts/generate.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "os" 7 | "path/filepath" 8 | "strings" 9 | ) 10 | 11 | func main() { 12 | types := []string{"string", "int64", "int32", "int16", "int8", "int", "uint64", "uint32", "uint16", "uint8", "uint", "float64", "float32", "bool", "interface"} 13 | 14 | // Read template 15 | cwd, err := os.Getwd() 16 | if err != nil { 17 | panic(err) 18 | } 19 | 20 | for _, t := range types { 21 | bytes, err := ioutil.ReadFile(filepath.Join(cwd, "slicer.template")) 22 | if err != nil { 23 | panic(err) 24 | } 25 | template := string(bytes) 26 | thisTemplate := template 27 | Type := t 28 | TypeTitle := strings.Title(t) 29 | 30 | if Type == "interface" { 31 | Type = "interface{}" 32 | } 33 | SlicerName := TypeTitle + "Slicer" 34 | 35 | // Type specific additions 36 | thisTemplate = fixup(thisTemplate, t) 37 | 38 | // Replace type 39 | thisTemplate = strings.ReplaceAll(thisTemplate, "_TYPE_", Type) 40 | thisTemplate = strings.ReplaceAll(thisTemplate, "_TYPETITLE_", TypeTitle) 41 | thisTemplate = strings.ReplaceAll(thisTemplate, "_SLICERNAME_", SlicerName) 42 | 43 | // Save file 44 | targetFile := filepath.Join(cwd, "..", t+".go") 45 | err = ioutil.WriteFile(targetFile, []byte(thisTemplate), 0644) 46 | if err != nil { 47 | panic(err) 48 | } 49 | } 50 | 51 | } 52 | 53 | func fixup(template string, t string) string { 54 | 55 | template = fixupJoin(template, t) 56 | template = fixupSort(template, t) 57 | 58 | return template 59 | } 60 | 61 | func fixupSort(template string, t string) string { 62 | // Sort String 63 | sortString := ` 64 | // Sort the slice values 65 | func (s *StringSlicer) Sort() { 66 | sort.Strings(s.slice) 67 | } 68 | ` 69 | sortDefault := ` 70 | // Sort the slice values 71 | func (s *_SLICERNAME_) Sort() { 72 | sort.Slice(s.slice, func(i, j int) bool { return s.slice[i] < s.slice[j] }) 73 | }` 74 | 75 | switch t { 76 | case "string": 77 | template += sortString 78 | template = addImport(template, "sort") 79 | case "interface", "bool": //Ignore 80 | default: 81 | template += sortDefault 82 | template = addImport(template, "sort") 83 | } 84 | return template 85 | } 86 | 87 | func fixupJoin(template string, t string) string { 88 | 89 | //Join 90 | joinGeneric := ` 91 | // Join returns a string with the slicer elements separated by the given separator 92 | func (s *_SLICERNAME_) Join(separator string) string { 93 | var builder strings.Builder 94 | 95 | // Shortcut no elements 96 | if len(s.slice) == 0 { 97 | return "" 98 | } 99 | 100 | // Iterate over length - 1 101 | index := 0 102 | for index = 0; index < len(s.slice)-1; index++ { 103 | builder.WriteString(fmt.Sprintf("%v%s", s.slice[index], separator)) 104 | } 105 | builder.WriteString(fmt.Sprintf("%v", s.slice[index])) 106 | result := builder.String() 107 | return result 108 | }` 109 | joinString := ` 110 | // Join returns a string with the slicer elements separated by the given separator 111 | func (s *StringSlicer) Join(separator string) string { 112 | return strings.Join(s.slice, separator) 113 | }` 114 | 115 | switch t { 116 | case "string": 117 | template += joinString 118 | // template = addImport(template, "sort") 119 | default: 120 | template += joinGeneric 121 | template = addImport(template, "fmt") 122 | } 123 | return template 124 | } 125 | 126 | func addImport(template string, name string) string { 127 | newText := fmt.Sprintf("// Imports\nimport \"%s\"", name) 128 | return strings.ReplaceAll(template, "// Imports", newText) 129 | } 130 | -------------------------------------------------------------------------------- /scripts/slicer.template: -------------------------------------------------------------------------------- 1 | // Package slicer contains utility classes for handling slices 2 | package slicer 3 | 4 | // Imports 5 | import "strings" 6 | 7 | // _SLICERNAME_ handles slices of _TYPE_ 8 | type _SLICERNAME_ struct { 9 | slice []_TYPE_ 10 | } 11 | 12 | // _TYPETITLE_ creates a new _SLICERNAME_ 13 | func _TYPETITLE_(slice ...[]_TYPE_) *_SLICERNAME_ { 14 | if len(slice) > 0 { 15 | return &_SLICERNAME_{slice: slice[0]} 16 | } 17 | return &_SLICERNAME_{} 18 | } 19 | 20 | // Add a _TYPE_ value to the slicer 21 | func (s *_SLICERNAME_) Add(value _TYPE_, additional ..._TYPE_) { 22 | s.slice = append(s.slice, value) 23 | s.slice = append(s.slice, additional...) 24 | } 25 | 26 | // AddUnique adds a _TYPE_ value to the slicer if it does not already exist 27 | func (s *_SLICERNAME_) AddUnique(value _TYPE_, additional ..._TYPE_) { 28 | 29 | if !s.Contains(value) { 30 | s.slice = append(s.slice, value) 31 | } 32 | 33 | // Add additional values 34 | for _, value := range additional { 35 | if !s.Contains(value) { 36 | s.slice = append(s.slice, value) 37 | } 38 | } 39 | } 40 | 41 | // AddSlice adds a _TYPE_ slice to the slicer 42 | func (s *_SLICERNAME_) AddSlice(value []_TYPE_) { 43 | s.slice = append(s.slice, value...) 44 | } 45 | 46 | // AsSlice returns the slice 47 | func (s *_SLICERNAME_) AsSlice() []_TYPE_ { 48 | return s.slice 49 | } 50 | 51 | // AddSlicer appends a _SLICERNAME_ to the slicer 52 | func (s *_SLICERNAME_) AddSlicer(value *_SLICERNAME_) { 53 | s.slice = append(s.slice, value.AsSlice()...) 54 | } 55 | 56 | // Filter the slice based on the given function 57 | func (s *_SLICERNAME_) Filter(fn func(_TYPE_) bool) *_SLICERNAME_ { 58 | result := &_SLICERNAME_{} 59 | for _, elem := range s.slice { 60 | if fn(elem) { 61 | result.Add(elem) 62 | } 63 | } 64 | return result 65 | } 66 | 67 | // Each runs a function on every element of the slice 68 | func (s *_SLICERNAME_) Each(fn func(_TYPE_)) { 69 | for _, elem := range s.slice { 70 | fn(elem) 71 | } 72 | } 73 | 74 | // Contains indicates if the given value is in the slice 75 | func (s *_SLICERNAME_) Contains(matcher _TYPE_) bool { 76 | result := false 77 | for _, elem := range s.slice { 78 | if elem == matcher { 79 | result = true 80 | } 81 | } 82 | return result 83 | } 84 | 85 | // Length returns the number of elements in the slice 86 | func (s *_SLICERNAME_) Length() int { 87 | return len(s.slice) 88 | } 89 | 90 | // Clear all elements in the slice 91 | func (s *_SLICERNAME_) Clear() { 92 | s.slice = []_TYPE_{} 93 | } 94 | 95 | // Deduplicate removes duplicate values from the slice 96 | func (s *_SLICERNAME_) Deduplicate() { 97 | 98 | result := &_SLICERNAME_{} 99 | 100 | for _, elem := range s.slice { 101 | if !result.Contains(elem) { 102 | result.Add(elem) 103 | } 104 | } 105 | 106 | s.slice = result.AsSlice() 107 | } 108 | -------------------------------------------------------------------------------- /string.go: -------------------------------------------------------------------------------- 1 | // Package slicer contains utility classes for handling slices 2 | package slicer 3 | 4 | // Imports 5 | import "sort" 6 | import "strings" 7 | 8 | // StringSlicer handles slices of string 9 | type StringSlicer struct { 10 | slice []string 11 | } 12 | 13 | // String creates a new StringSlicer 14 | func String(slice ...[]string) *StringSlicer { 15 | if len(slice) > 0 { 16 | return &StringSlicer{slice: slice[0]} 17 | } 18 | return &StringSlicer{} 19 | } 20 | 21 | // Add a string value to the slicer 22 | func (s *StringSlicer) Add(value string, additional ...string) { 23 | s.slice = append(s.slice, value) 24 | s.slice = append(s.slice, additional...) 25 | } 26 | 27 | // AddUnique adds a string value to the slicer if it does not already exist 28 | func (s *StringSlicer) AddUnique(value string, additional ...string) { 29 | 30 | if !s.Contains(value) { 31 | s.slice = append(s.slice, value) 32 | } 33 | 34 | // Add additional values 35 | for _, value := range additional { 36 | if !s.Contains(value) { 37 | s.slice = append(s.slice, value) 38 | } 39 | } 40 | } 41 | 42 | // AddSlice adds a string slice to the slicer 43 | func (s *StringSlicer) AddSlice(value []string) { 44 | s.slice = append(s.slice, value...) 45 | } 46 | 47 | // AsSlice returns the slice 48 | func (s *StringSlicer) AsSlice() []string { 49 | return s.slice 50 | } 51 | 52 | // AddSlicer appends a StringSlicer to the slicer 53 | func (s *StringSlicer) AddSlicer(value *StringSlicer) { 54 | s.slice = append(s.slice, value.AsSlice()...) 55 | } 56 | 57 | // Filter the slice based on the given function 58 | func (s *StringSlicer) Filter(fn func(string) bool) *StringSlicer { 59 | result := &StringSlicer{} 60 | for _, elem := range s.slice { 61 | if fn(elem) { 62 | result.Add(elem) 63 | } 64 | } 65 | return result 66 | } 67 | 68 | // Each runs a function on every element of the slice 69 | func (s *StringSlicer) Each(fn func(string)) { 70 | for _, elem := range s.slice { 71 | fn(elem) 72 | } 73 | } 74 | 75 | // Contains indicates if the given value is in the slice 76 | func (s *StringSlicer) Contains(matcher string) bool { 77 | result := false 78 | for _, elem := range s.slice { 79 | if elem == matcher { 80 | result = true 81 | } 82 | } 83 | return result 84 | } 85 | 86 | // Length returns the number of elements in the slice 87 | func (s *StringSlicer) Length() int { 88 | return len(s.slice) 89 | } 90 | 91 | // Clear all elements in the slice 92 | func (s *StringSlicer) Clear() { 93 | s.slice = []string{} 94 | } 95 | 96 | // Deduplicate removes duplicate values from the slice 97 | func (s *StringSlicer) Deduplicate() { 98 | 99 | result := &StringSlicer{} 100 | 101 | for _, elem := range s.slice { 102 | if !result.Contains(elem) { 103 | result.Add(elem) 104 | } 105 | } 106 | 107 | s.slice = result.AsSlice() 108 | } 109 | 110 | // Join returns a string with the slicer elements separated by the given separator 111 | func (s *StringSlicer) Join(separator string) string { 112 | return strings.Join(s.slice, separator) 113 | } 114 | 115 | // Sort the slice values 116 | func (s *StringSlicer) Sort() { 117 | sort.Strings(s.slice) 118 | } 119 | -------------------------------------------------------------------------------- /string_test.go: -------------------------------------------------------------------------------- 1 | package slicer 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | ) 7 | 8 | func TestStringFilter(t *testing.T) { 9 | 10 | s := String() 11 | s.Add("one") 12 | s.Add("two") 13 | s.Add("one") 14 | s.Add("three") 15 | s.Add("one") 16 | 17 | expected := "one one one" 18 | filtered := s.Filter(func(v string) bool { 19 | return v == "one" 20 | }) 21 | actual := strings.Join(filtered.AsSlice(), " ") 22 | if expected != actual { 23 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 24 | } 25 | } 26 | 27 | func TestStringEach(t *testing.T) { 28 | 29 | s := String() 30 | s.Add("one") 31 | s.Add("two") 32 | s.Add("three") 33 | 34 | result := String() 35 | s.Each(func(elem string) { 36 | result.Add(elem + "!") 37 | }) 38 | expected := "one! two! three!" 39 | actual := strings.Join(result.AsSlice(), " ") 40 | if expected != actual { 41 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 42 | } 43 | } 44 | 45 | // TestOptionalStringSlice tests when you construct a String with 46 | // an existing slice 47 | func TestOptionalStringSlice(t *testing.T) { 48 | data := []string{"one", "two", "three"} 49 | s := String(data) 50 | 51 | result := "" 52 | s.Each(func(elem string) { 53 | result += elem 54 | }) 55 | expected := "onetwothree" 56 | if expected != result { 57 | t.Errorf("Expected '%s', but got '%s'", expected, result) 58 | } 59 | } 60 | 61 | // TestSort tests that the slicer can be sorted 62 | func TestSort(t *testing.T) { 63 | data := []string{"cat", "bat", "dog", "arachnid"} 64 | s := String(data) 65 | s.Sort() 66 | result := "" 67 | s.Each(func(elem string) { 68 | result += elem 69 | }) 70 | expected := "arachnidbatcatdog" 71 | if expected != result { 72 | t.Errorf("Expected '%s', but got '%s'", expected, result) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /uint.go: -------------------------------------------------------------------------------- 1 | // Package slicer contains utility classes for handling slices 2 | package slicer 3 | 4 | // Imports 5 | import "sort" 6 | import "fmt" 7 | import "strings" 8 | 9 | // UintSlicer handles slices of uint 10 | type UintSlicer struct { 11 | slice []uint 12 | } 13 | 14 | // Uint creates a new UintSlicer 15 | func Uint(slice ...[]uint) *UintSlicer { 16 | if len(slice) > 0 { 17 | return &UintSlicer{slice: slice[0]} 18 | } 19 | return &UintSlicer{} 20 | } 21 | 22 | // Add a uint value to the slicer 23 | func (s *UintSlicer) Add(value uint, additional ...uint) { 24 | s.slice = append(s.slice, value) 25 | s.slice = append(s.slice, additional...) 26 | } 27 | 28 | // AddUnique adds a uint value to the slicer if it does not already exist 29 | func (s *UintSlicer) AddUnique(value uint, additional ...uint) { 30 | 31 | if !s.Contains(value) { 32 | s.slice = append(s.slice, value) 33 | } 34 | 35 | // Add additional values 36 | for _, value := range additional { 37 | if !s.Contains(value) { 38 | s.slice = append(s.slice, value) 39 | } 40 | } 41 | } 42 | 43 | // AddSlice adds a uint slice to the slicer 44 | func (s *UintSlicer) AddSlice(value []uint) { 45 | s.slice = append(s.slice, value...) 46 | } 47 | 48 | // AsSlice returns the slice 49 | func (s *UintSlicer) AsSlice() []uint { 50 | return s.slice 51 | } 52 | 53 | // AddSlicer appends a UintSlicer to the slicer 54 | func (s *UintSlicer) AddSlicer(value *UintSlicer) { 55 | s.slice = append(s.slice, value.AsSlice()...) 56 | } 57 | 58 | // Filter the slice based on the given function 59 | func (s *UintSlicer) Filter(fn func(uint) bool) *UintSlicer { 60 | result := &UintSlicer{} 61 | for _, elem := range s.slice { 62 | if fn(elem) { 63 | result.Add(elem) 64 | } 65 | } 66 | return result 67 | } 68 | 69 | // Each runs a function on every element of the slice 70 | func (s *UintSlicer) Each(fn func(uint)) { 71 | for _, elem := range s.slice { 72 | fn(elem) 73 | } 74 | } 75 | 76 | // Contains indicates if the given value is in the slice 77 | func (s *UintSlicer) Contains(matcher uint) bool { 78 | result := false 79 | for _, elem := range s.slice { 80 | if elem == matcher { 81 | result = true 82 | } 83 | } 84 | return result 85 | } 86 | 87 | // Length returns the number of elements in the slice 88 | func (s *UintSlicer) Length() int { 89 | return len(s.slice) 90 | } 91 | 92 | // Clear all elements in the slice 93 | func (s *UintSlicer) Clear() { 94 | s.slice = []uint{} 95 | } 96 | 97 | // Deduplicate removes duplicate values from the slice 98 | func (s *UintSlicer) Deduplicate() { 99 | 100 | result := &UintSlicer{} 101 | 102 | for _, elem := range s.slice { 103 | if !result.Contains(elem) { 104 | result.Add(elem) 105 | } 106 | } 107 | 108 | s.slice = result.AsSlice() 109 | } 110 | 111 | // Join returns a string with the slicer elements separated by the given separator 112 | func (s *UintSlicer) Join(separator string) string { 113 | var builder strings.Builder 114 | 115 | // Shortcut no elements 116 | if len(s.slice) == 0 { 117 | return "" 118 | } 119 | 120 | // Iterate over length - 1 121 | index := 0 122 | for index = 0; index < len(s.slice)-1; index++ { 123 | builder.WriteString(fmt.Sprintf("%v%s", s.slice[index], separator)) 124 | } 125 | builder.WriteString(fmt.Sprintf("%v", s.slice[index])) 126 | result := builder.String() 127 | return result 128 | } 129 | 130 | // Sort the slice values 131 | func (s *UintSlicer) Sort() { 132 | sort.Slice(s.slice, func(i, j int) bool { return s.slice[i] < s.slice[j] }) 133 | } 134 | -------------------------------------------------------------------------------- /uint16.go: -------------------------------------------------------------------------------- 1 | // Package slicer contains utility classes for handling slices 2 | package slicer 3 | 4 | // Imports 5 | import "sort" 6 | import "fmt" 7 | import "strings" 8 | 9 | // Uint16Slicer handles slices of uint16 10 | type Uint16Slicer struct { 11 | slice []uint16 12 | } 13 | 14 | // Uint16 creates a new Uint16Slicer 15 | func Uint16(slice ...[]uint16) *Uint16Slicer { 16 | if len(slice) > 0 { 17 | return &Uint16Slicer{slice: slice[0]} 18 | } 19 | return &Uint16Slicer{} 20 | } 21 | 22 | // Add a uint16 value to the slicer 23 | func (s *Uint16Slicer) Add(value uint16, additional ...uint16) { 24 | s.slice = append(s.slice, value) 25 | s.slice = append(s.slice, additional...) 26 | } 27 | 28 | // AddUnique adds a uint16 value to the slicer if it does not already exist 29 | func (s *Uint16Slicer) AddUnique(value uint16, additional ...uint16) { 30 | 31 | if !s.Contains(value) { 32 | s.slice = append(s.slice, value) 33 | } 34 | 35 | // Add additional values 36 | for _, value := range additional { 37 | if !s.Contains(value) { 38 | s.slice = append(s.slice, value) 39 | } 40 | } 41 | } 42 | 43 | // AddSlice adds a uint16 slice to the slicer 44 | func (s *Uint16Slicer) AddSlice(value []uint16) { 45 | s.slice = append(s.slice, value...) 46 | } 47 | 48 | // AsSlice returns the slice 49 | func (s *Uint16Slicer) AsSlice() []uint16 { 50 | return s.slice 51 | } 52 | 53 | // AddSlicer appends a Uint16Slicer to the slicer 54 | func (s *Uint16Slicer) AddSlicer(value *Uint16Slicer) { 55 | s.slice = append(s.slice, value.AsSlice()...) 56 | } 57 | 58 | // Filter the slice based on the given function 59 | func (s *Uint16Slicer) Filter(fn func(uint16) bool) *Uint16Slicer { 60 | result := &Uint16Slicer{} 61 | for _, elem := range s.slice { 62 | if fn(elem) { 63 | result.Add(elem) 64 | } 65 | } 66 | return result 67 | } 68 | 69 | // Each runs a function on every element of the slice 70 | func (s *Uint16Slicer) Each(fn func(uint16)) { 71 | for _, elem := range s.slice { 72 | fn(elem) 73 | } 74 | } 75 | 76 | // Contains indicates if the given value is in the slice 77 | func (s *Uint16Slicer) Contains(matcher uint16) bool { 78 | result := false 79 | for _, elem := range s.slice { 80 | if elem == matcher { 81 | result = true 82 | } 83 | } 84 | return result 85 | } 86 | 87 | // Length returns the number of elements in the slice 88 | func (s *Uint16Slicer) Length() int { 89 | return len(s.slice) 90 | } 91 | 92 | // Clear all elements in the slice 93 | func (s *Uint16Slicer) Clear() { 94 | s.slice = []uint16{} 95 | } 96 | 97 | // Deduplicate removes duplicate values from the slice 98 | func (s *Uint16Slicer) Deduplicate() { 99 | 100 | result := &Uint16Slicer{} 101 | 102 | for _, elem := range s.slice { 103 | if !result.Contains(elem) { 104 | result.Add(elem) 105 | } 106 | } 107 | 108 | s.slice = result.AsSlice() 109 | } 110 | 111 | // Join returns a string with the slicer elements separated by the given separator 112 | func (s *Uint16Slicer) Join(separator string) string { 113 | var builder strings.Builder 114 | 115 | // Shortcut no elements 116 | if len(s.slice) == 0 { 117 | return "" 118 | } 119 | 120 | // Iterate over length - 1 121 | index := 0 122 | for index = 0; index < len(s.slice)-1; index++ { 123 | builder.WriteString(fmt.Sprintf("%v%s", s.slice[index], separator)) 124 | } 125 | builder.WriteString(fmt.Sprintf("%v", s.slice[index])) 126 | result := builder.String() 127 | return result 128 | } 129 | 130 | // Sort the slice values 131 | func (s *Uint16Slicer) Sort() { 132 | sort.Slice(s.slice, func(i, j int) bool { return s.slice[i] < s.slice[j] }) 133 | } 134 | -------------------------------------------------------------------------------- /uint16_test.go: -------------------------------------------------------------------------------- 1 | package slicer 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/matryer/is" 6 | "testing" 7 | ) 8 | 9 | func TestUint16Add(t *testing.T) { 10 | 11 | s := Uint16() 12 | s.Add(1) 13 | s.Add(2) 14 | 15 | expected := "[1,2]" 16 | actual, _ := json.Marshal(s.AsSlice()) 17 | if expected != string(actual) { 18 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 19 | } 20 | 21 | s.Clear() 22 | s.Add(1, 2) 23 | 24 | expected = "[1,2]" 25 | actual, _ = json.Marshal(s.AsSlice()) 26 | if expected != string(actual) { 27 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 28 | } 29 | } 30 | 31 | func TestUint16Length(t *testing.T) { 32 | is2 := is.New(t) 33 | s := Uint16() 34 | s.Add(1) 35 | s.Add(2) 36 | 37 | is2.Equal(s.Length(), 2) 38 | } 39 | func TestUint16Deduplicate(t *testing.T) { 40 | is2 := is.New(t) 41 | s := Uint16() 42 | s.Add(1) 43 | s.Add(2) 44 | s.Add(2) 45 | s.Add(2) 46 | 47 | is2.Equal(s.Length(), 4) 48 | is2.Equal(s.AsSlice(), []uint16{1, 2, 2, 2}) 49 | s.Deduplicate() 50 | is2.Equal(s.Length(), 2) 51 | is2.Equal(s.AsSlice(), []uint16{1, 2}) 52 | } 53 | func TestUint16AddUnique(t *testing.T) { 54 | 55 | s := Uint16() 56 | s.AddUnique(1) 57 | s.AddUnique(2) 58 | s.AddUnique(2) 59 | s.AddUnique(2) 60 | 61 | expected := "[1,2]" 62 | actual, _ := json.Marshal(s.AsSlice()) 63 | if expected != string(actual) { 64 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 65 | } 66 | 67 | s.Clear() 68 | s.AddUnique(1, 2, 1, 2, 2, 1) 69 | 70 | expected = "[1,2]" 71 | actual, _ = json.Marshal(s.AsSlice()) 72 | if expected != string(actual) { 73 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 74 | } 75 | } 76 | 77 | func TestUint16AddSlice(t *testing.T) { 78 | 79 | s := Uint16() 80 | s.Add(1) 81 | s.Add(2) 82 | 83 | extras := []uint16{3, 4} 84 | 85 | s.AddSlice(extras) 86 | 87 | expected := "[1,2,3,4]" 88 | actual, _ := json.Marshal(s.AsSlice()) 89 | if expected != string(actual) { 90 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 91 | } 92 | } 93 | 94 | func TestUint16AddSlicer(t *testing.T) { 95 | 96 | s := Uint16() 97 | s.Add(1) 98 | s.Add(2) 99 | 100 | p := Uint16() 101 | p.Add(3) 102 | p.Add(4) 103 | 104 | s.AddSlicer(p) 105 | 106 | expected := "[1,2,3,4]" 107 | actual, _ := json.Marshal(s.AsSlice()) 108 | if expected != string(actual) { 109 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 110 | } 111 | } 112 | func TestUint16Filter(t *testing.T) { 113 | 114 | s := Uint16() 115 | s.Add(18) 116 | s.Add(180) 117 | s.Add(1) 118 | s.Add(10) 119 | s.Add(20) 120 | s.Add(3) 121 | s.Add(29) 122 | 123 | result := s.Filter(func(i uint16) bool { 124 | return i > 19 125 | }) 126 | 127 | expected := "[180,20,29]" 128 | actual, _ := json.Marshal(result.AsSlice()) 129 | if expected != string(actual) { 130 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 131 | } 132 | } 133 | func TestUint16Each(t *testing.T) { 134 | 135 | s := Uint16() 136 | s.Add(18) 137 | s.Add(10) 138 | s.Add(1) 139 | s.Add(10) 140 | s.Add(20) 141 | s.Add(3) 142 | s.Add(29) 143 | 144 | var result uint16 145 | 146 | s.Each(func(i uint16) { 147 | result = result + i 148 | }) 149 | 150 | var expected uint16 = 91 151 | if expected != result { 152 | t.Errorf("Expected '%d', but got '%d'", expected, result) 153 | } 154 | } 155 | 156 | // TestOptionalUint16Slice tests when you construct a Uint16 with 157 | // an existing slice 158 | func TestOptionalUint16Slice(t *testing.T) { 159 | data := []uint16{1, 2, 3} 160 | s := Uint16(data) 161 | 162 | var result uint16 = 0 163 | s.Each(func(elem uint16) { 164 | result += elem 165 | }) 166 | var expected uint16 = 6 167 | if expected != result { 168 | t.Errorf("Expected '%d', but got '%d'", expected, result) 169 | } 170 | } 171 | 172 | // TestUint16Sort tests that the slicer can be sorted 173 | func TestUint16Sort(t *testing.T) { 174 | is2 := is.New(t) 175 | data := []uint16{5, 4, 3, 2, 1} 176 | s := Uint16(data) 177 | s.Sort() 178 | result := s.Join(",") 179 | expected := "1,2,3,4,5" 180 | is2.Equal(result, expected) 181 | s.Clear() 182 | is2.Equal(s.Join(""), "") 183 | } 184 | -------------------------------------------------------------------------------- /uint32.go: -------------------------------------------------------------------------------- 1 | // Package slicer contains utility classes for handling slices 2 | package slicer 3 | 4 | // Imports 5 | import "sort" 6 | import "fmt" 7 | import "strings" 8 | 9 | // Uint32Slicer handles slices of uint32 10 | type Uint32Slicer struct { 11 | slice []uint32 12 | } 13 | 14 | // Uint32 creates a new Uint32Slicer 15 | func Uint32(slice ...[]uint32) *Uint32Slicer { 16 | if len(slice) > 0 { 17 | return &Uint32Slicer{slice: slice[0]} 18 | } 19 | return &Uint32Slicer{} 20 | } 21 | 22 | // Add a uint32 value to the slicer 23 | func (s *Uint32Slicer) Add(value uint32, additional ...uint32) { 24 | s.slice = append(s.slice, value) 25 | s.slice = append(s.slice, additional...) 26 | } 27 | 28 | // AddUnique adds a uint32 value to the slicer if it does not already exist 29 | func (s *Uint32Slicer) AddUnique(value uint32, additional ...uint32) { 30 | 31 | if !s.Contains(value) { 32 | s.slice = append(s.slice, value) 33 | } 34 | 35 | // Add additional values 36 | for _, value := range additional { 37 | if !s.Contains(value) { 38 | s.slice = append(s.slice, value) 39 | } 40 | } 41 | } 42 | 43 | // AddSlice adds a uint32 slice to the slicer 44 | func (s *Uint32Slicer) AddSlice(value []uint32) { 45 | s.slice = append(s.slice, value...) 46 | } 47 | 48 | // AsSlice returns the slice 49 | func (s *Uint32Slicer) AsSlice() []uint32 { 50 | return s.slice 51 | } 52 | 53 | // AddSlicer appends a Uint32Slicer to the slicer 54 | func (s *Uint32Slicer) AddSlicer(value *Uint32Slicer) { 55 | s.slice = append(s.slice, value.AsSlice()...) 56 | } 57 | 58 | // Filter the slice based on the given function 59 | func (s *Uint32Slicer) Filter(fn func(uint32) bool) *Uint32Slicer { 60 | result := &Uint32Slicer{} 61 | for _, elem := range s.slice { 62 | if fn(elem) { 63 | result.Add(elem) 64 | } 65 | } 66 | return result 67 | } 68 | 69 | // Each runs a function on every element of the slice 70 | func (s *Uint32Slicer) Each(fn func(uint32)) { 71 | for _, elem := range s.slice { 72 | fn(elem) 73 | } 74 | } 75 | 76 | // Contains indicates if the given value is in the slice 77 | func (s *Uint32Slicer) Contains(matcher uint32) bool { 78 | result := false 79 | for _, elem := range s.slice { 80 | if elem == matcher { 81 | result = true 82 | } 83 | } 84 | return result 85 | } 86 | 87 | // Length returns the number of elements in the slice 88 | func (s *Uint32Slicer) Length() int { 89 | return len(s.slice) 90 | } 91 | 92 | // Clear all elements in the slice 93 | func (s *Uint32Slicer) Clear() { 94 | s.slice = []uint32{} 95 | } 96 | 97 | // Deduplicate removes duplicate values from the slice 98 | func (s *Uint32Slicer) Deduplicate() { 99 | 100 | result := &Uint32Slicer{} 101 | 102 | for _, elem := range s.slice { 103 | if !result.Contains(elem) { 104 | result.Add(elem) 105 | } 106 | } 107 | 108 | s.slice = result.AsSlice() 109 | } 110 | 111 | // Join returns a string with the slicer elements separated by the given separator 112 | func (s *Uint32Slicer) Join(separator string) string { 113 | var builder strings.Builder 114 | 115 | // Shortcut no elements 116 | if len(s.slice) == 0 { 117 | return "" 118 | } 119 | 120 | // Iterate over length - 1 121 | index := 0 122 | for index = 0; index < len(s.slice)-1; index++ { 123 | builder.WriteString(fmt.Sprintf("%v%s", s.slice[index], separator)) 124 | } 125 | builder.WriteString(fmt.Sprintf("%v", s.slice[index])) 126 | result := builder.String() 127 | return result 128 | } 129 | 130 | // Sort the slice values 131 | func (s *Uint32Slicer) Sort() { 132 | sort.Slice(s.slice, func(i, j int) bool { return s.slice[i] < s.slice[j] }) 133 | } 134 | -------------------------------------------------------------------------------- /uint32_test.go: -------------------------------------------------------------------------------- 1 | package slicer 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/matryer/is" 6 | "testing" 7 | ) 8 | 9 | func TestUint32Add(t *testing.T) { 10 | 11 | s := Uint32() 12 | s.Add(1) 13 | s.Add(2) 14 | 15 | expected := "[1,2]" 16 | actual, _ := json.Marshal(s.AsSlice()) 17 | if expected != string(actual) { 18 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 19 | } 20 | s.Clear() 21 | s.Add(1, 2) 22 | 23 | expected = "[1,2]" 24 | actual, _ = json.Marshal(s.AsSlice()) 25 | if expected != string(actual) { 26 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 27 | } 28 | } 29 | 30 | func TestUint32AddUnique(t *testing.T) { 31 | 32 | s := Uint32() 33 | s.AddUnique(1) 34 | s.AddUnique(2) 35 | s.AddUnique(2) 36 | s.AddUnique(2) 37 | 38 | expected := "[1,2]" 39 | actual, _ := json.Marshal(s.AsSlice()) 40 | if expected != string(actual) { 41 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 42 | } 43 | 44 | s.Clear() 45 | s.AddUnique(1, 2, 1, 2, 2, 1) 46 | 47 | expected = "[1,2]" 48 | actual, _ = json.Marshal(s.AsSlice()) 49 | if expected != string(actual) { 50 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 51 | } 52 | } 53 | 54 | func TestUint32AddSlice(t *testing.T) { 55 | 56 | s := Uint32() 57 | s.Add(1) 58 | s.Add(2) 59 | 60 | extras := []uint32{3, 4} 61 | 62 | s.AddSlice(extras) 63 | 64 | expected := "[1,2,3,4]" 65 | actual, _ := json.Marshal(s.AsSlice()) 66 | if expected != string(actual) { 67 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 68 | } 69 | } 70 | 71 | func TestUint32Length(t *testing.T) { 72 | is2 := is.New(t) 73 | s := Uint32() 74 | s.Add(1) 75 | s.Add(2) 76 | 77 | is2.Equal(s.Length(), 2) 78 | } 79 | 80 | func TestUint32Deduplicate(t *testing.T) { 81 | is2 := is.New(t) 82 | s := Uint32() 83 | s.Add(1) 84 | s.Add(2) 85 | s.Add(2) 86 | s.Add(2) 87 | 88 | is2.Equal(s.Length(), 4) 89 | is2.Equal(s.AsSlice(), []uint32{1, 2, 2, 2}) 90 | s.Deduplicate() 91 | is2.Equal(s.Length(), 2) 92 | is2.Equal(s.AsSlice(), []uint32{1, 2}) 93 | 94 | } 95 | func TestUint32AddSlicer(t *testing.T) { 96 | 97 | s := Uint32() 98 | s.Add(1) 99 | s.Add(2) 100 | 101 | p := Uint32() 102 | p.Add(3) 103 | p.Add(4) 104 | 105 | s.AddSlicer(p) 106 | 107 | expected := "[1,2,3,4]" 108 | actual, _ := json.Marshal(s.AsSlice()) 109 | if expected != string(actual) { 110 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 111 | } 112 | } 113 | 114 | func TestUint32Filter(t *testing.T) { 115 | 116 | s := Uint32() 117 | s.Add(18) 118 | s.Add(180) 119 | s.Add(1) 120 | s.Add(10) 121 | s.Add(20) 122 | s.Add(3) 123 | s.Add(29) 124 | 125 | result := s.Filter(func(i uint32) bool { 126 | return i > 19 127 | }) 128 | 129 | expected := "[180,20,29]" 130 | actual, _ := json.Marshal(result.AsSlice()) 131 | if expected != string(actual) { 132 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 133 | } 134 | } 135 | 136 | func TestUint32Each(t *testing.T) { 137 | 138 | s := Uint32() 139 | s.Add(18) 140 | s.Add(10) 141 | s.Add(1) 142 | s.Add(10) 143 | s.Add(20) 144 | s.Add(3) 145 | s.Add(29) 146 | 147 | var result uint32 148 | 149 | s.Each(func(i uint32) { 150 | result = result + i 151 | }) 152 | 153 | var expected uint32 = 91 154 | if expected != result { 155 | t.Errorf("Expected '%d', but got '%d'", expected, result) 156 | } 157 | } 158 | 159 | // TestOptionalUint32Slice tests when you construct a Uint32 with 160 | // an existing slice 161 | func TestOptionalUint32Slice(t *testing.T) { 162 | data := []uint32{1, 2, 3} 163 | s := Uint32(data) 164 | 165 | var result uint32 = 0 166 | s.Each(func(elem uint32) { 167 | result += elem 168 | }) 169 | var expected uint32 = 6 170 | if expected != result { 171 | t.Errorf("Expected '%d', but got '%d'", expected, result) 172 | } 173 | } 174 | 175 | // TestUint32Sort tests that the slicer can be sorted 176 | func TestUint32Sort(t *testing.T) { 177 | is2 := is.New(t) 178 | data := []uint32{5, 4, 3, 2, 1} 179 | s := Uint32(data) 180 | s.Sort() 181 | result := s.Join(",") 182 | expected := "1,2,3,4,5" 183 | is2.Equal(expected, result) 184 | s.Clear() 185 | is2.Equal(s.Join(""), "") 186 | } 187 | -------------------------------------------------------------------------------- /uint64.go: -------------------------------------------------------------------------------- 1 | // Package slicer contains utility classes for handling slices 2 | package slicer 3 | 4 | // Imports 5 | import "sort" 6 | import "fmt" 7 | import "strings" 8 | 9 | // Uint64Slicer handles slices of uint64 10 | type Uint64Slicer struct { 11 | slice []uint64 12 | } 13 | 14 | // Uint64 creates a new Uint64Slicer 15 | func Uint64(slice ...[]uint64) *Uint64Slicer { 16 | if len(slice) > 0 { 17 | return &Uint64Slicer{slice: slice[0]} 18 | } 19 | return &Uint64Slicer{} 20 | } 21 | 22 | // Add a uint64 value to the slicer 23 | func (s *Uint64Slicer) Add(value uint64, additional ...uint64) { 24 | s.slice = append(s.slice, value) 25 | s.slice = append(s.slice, additional...) 26 | } 27 | 28 | // AddUnique adds a uint64 value to the slicer if it does not already exist 29 | func (s *Uint64Slicer) AddUnique(value uint64, additional ...uint64) { 30 | 31 | if !s.Contains(value) { 32 | s.slice = append(s.slice, value) 33 | } 34 | 35 | // Add additional values 36 | for _, value := range additional { 37 | if !s.Contains(value) { 38 | s.slice = append(s.slice, value) 39 | } 40 | } 41 | } 42 | 43 | // AddSlice adds a uint64 slice to the slicer 44 | func (s *Uint64Slicer) AddSlice(value []uint64) { 45 | s.slice = append(s.slice, value...) 46 | } 47 | 48 | // AsSlice returns the slice 49 | func (s *Uint64Slicer) AsSlice() []uint64 { 50 | return s.slice 51 | } 52 | 53 | // AddSlicer appends a Uint64Slicer to the slicer 54 | func (s *Uint64Slicer) AddSlicer(value *Uint64Slicer) { 55 | s.slice = append(s.slice, value.AsSlice()...) 56 | } 57 | 58 | // Filter the slice based on the given function 59 | func (s *Uint64Slicer) Filter(fn func(uint64) bool) *Uint64Slicer { 60 | result := &Uint64Slicer{} 61 | for _, elem := range s.slice { 62 | if fn(elem) { 63 | result.Add(elem) 64 | } 65 | } 66 | return result 67 | } 68 | 69 | // Each runs a function on every element of the slice 70 | func (s *Uint64Slicer) Each(fn func(uint64)) { 71 | for _, elem := range s.slice { 72 | fn(elem) 73 | } 74 | } 75 | 76 | // Contains indicates if the given value is in the slice 77 | func (s *Uint64Slicer) Contains(matcher uint64) bool { 78 | result := false 79 | for _, elem := range s.slice { 80 | if elem == matcher { 81 | result = true 82 | } 83 | } 84 | return result 85 | } 86 | 87 | // Length returns the number of elements in the slice 88 | func (s *Uint64Slicer) Length() int { 89 | return len(s.slice) 90 | } 91 | 92 | // Clear all elements in the slice 93 | func (s *Uint64Slicer) Clear() { 94 | s.slice = []uint64{} 95 | } 96 | 97 | // Deduplicate removes duplicate values from the slice 98 | func (s *Uint64Slicer) Deduplicate() { 99 | 100 | result := &Uint64Slicer{} 101 | 102 | for _, elem := range s.slice { 103 | if !result.Contains(elem) { 104 | result.Add(elem) 105 | } 106 | } 107 | 108 | s.slice = result.AsSlice() 109 | } 110 | 111 | // Join returns a string with the slicer elements separated by the given separator 112 | func (s *Uint64Slicer) Join(separator string) string { 113 | var builder strings.Builder 114 | 115 | // Shortcut no elements 116 | if len(s.slice) == 0 { 117 | return "" 118 | } 119 | 120 | // Iterate over length - 1 121 | index := 0 122 | for index = 0; index < len(s.slice)-1; index++ { 123 | builder.WriteString(fmt.Sprintf("%v%s", s.slice[index], separator)) 124 | } 125 | builder.WriteString(fmt.Sprintf("%v", s.slice[index])) 126 | result := builder.String() 127 | return result 128 | } 129 | 130 | // Sort the slice values 131 | func (s *Uint64Slicer) Sort() { 132 | sort.Slice(s.slice, func(i, j int) bool { return s.slice[i] < s.slice[j] }) 133 | } 134 | -------------------------------------------------------------------------------- /uint64_test.go: -------------------------------------------------------------------------------- 1 | package slicer 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/matryer/is" 6 | "testing" 7 | ) 8 | 9 | func TestUint64Add(t *testing.T) { 10 | 11 | s := Uint64() 12 | s.Add(1) 13 | s.Add(2) 14 | 15 | expected := "[1,2]" 16 | actual, _ := json.Marshal(s.AsSlice()) 17 | if expected != string(actual) { 18 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 19 | } 20 | s.Clear() 21 | s.Add(1, 2) 22 | 23 | expected = "[1,2]" 24 | actual, _ = json.Marshal(s.AsSlice()) 25 | if expected != string(actual) { 26 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 27 | } 28 | } 29 | func TestUint64AddUnique(t *testing.T) { 30 | 31 | s := Uint64() 32 | s.AddUnique(1) 33 | s.AddUnique(2) 34 | s.AddUnique(2) 35 | s.AddUnique(2) 36 | 37 | expected := "[1,2]" 38 | actual, _ := json.Marshal(s.AsSlice()) 39 | if expected != string(actual) { 40 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 41 | } 42 | 43 | s.Clear() 44 | s.AddUnique(1, 2, 1, 2, 2, 1) 45 | 46 | expected = "[1,2]" 47 | actual, _ = json.Marshal(s.AsSlice()) 48 | if expected != string(actual) { 49 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 50 | } 51 | } 52 | 53 | func TestUint64AddSlice(t *testing.T) { 54 | 55 | s := Uint64() 56 | s.Add(1) 57 | s.Add(2) 58 | 59 | extras := []uint64{3, 4} 60 | 61 | s.AddSlice(extras) 62 | 63 | expected := "[1,2,3,4]" 64 | actual, _ := json.Marshal(s.AsSlice()) 65 | if expected != string(actual) { 66 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 67 | } 68 | } 69 | 70 | func TestUint64AddSlicer(t *testing.T) { 71 | 72 | s := Uint64() 73 | s.Add(1) 74 | s.Add(2) 75 | 76 | p := Uint64() 77 | p.Add(3) 78 | p.Add(4) 79 | 80 | s.AddSlicer(p) 81 | 82 | expected := "[1,2,3,4]" 83 | actual, _ := json.Marshal(s.AsSlice()) 84 | if expected != string(actual) { 85 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 86 | } 87 | } 88 | 89 | func TestUint64Filter(t *testing.T) { 90 | 91 | s := Uint64() 92 | s.Add(18) 93 | s.Add(180) 94 | s.Add(1) 95 | s.Add(10) 96 | s.Add(20) 97 | s.Add(3) 98 | s.Add(29) 99 | 100 | result := s.Filter(func(i uint64) bool { 101 | return i > 19 102 | }) 103 | 104 | expected := "[180,20,29]" 105 | actual, _ := json.Marshal(result.AsSlice()) 106 | if expected != string(actual) { 107 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 108 | } 109 | } 110 | 111 | func TestUint64Each(t *testing.T) { 112 | 113 | s := Uint64() 114 | s.Add(18) 115 | s.Add(10) 116 | s.Add(1) 117 | s.Add(10) 118 | s.Add(20) 119 | s.Add(3) 120 | s.Add(29) 121 | 122 | var result uint64 123 | 124 | s.Each(func(i uint64) { 125 | result = result + i 126 | }) 127 | 128 | var expected uint64 = 91 129 | if expected != result { 130 | t.Errorf("Expected '%d', but got '%d'", expected, result) 131 | } 132 | } 133 | 134 | // TestOptionalUint64Slice tests when you construct a Uint64 with 135 | // an existing slice 136 | func TestOptionalUint64Slice(t *testing.T) { 137 | data := []uint64{1, 2, 3} 138 | s := Uint64(data) 139 | 140 | var result uint64 = 0 141 | s.Each(func(elem uint64) { 142 | result += elem 143 | }) 144 | var expected uint64 = 6 145 | if expected != result { 146 | t.Errorf("Expected '%d', but got '%d'", expected, result) 147 | } 148 | } 149 | func TestUint64Deduplicate(t *testing.T) { 150 | is2 := is.New(t) 151 | s := Uint64() 152 | s.Add(1) 153 | s.Add(2) 154 | s.Add(2) 155 | s.Add(2) 156 | 157 | is2.Equal(s.Length(), 4) 158 | is2.Equal(s.AsSlice(), []uint64{1, 2, 2, 2}) 159 | s.Deduplicate() 160 | is2.Equal(s.Length(), 2) 161 | is2.Equal(s.AsSlice(), []uint64{1, 2}) 162 | } 163 | func TestUint64Length(t *testing.T) { 164 | is2 := is.New(t) 165 | s := Uint64() 166 | s.Add(1) 167 | s.Add(2) 168 | 169 | is2.Equal(s.Length(), 2) 170 | } 171 | 172 | // TestUint64Sort tests that the slicer can be sorted 173 | func TestUint64Sort(t *testing.T) { 174 | is2 := is.New(t) 175 | data := []uint64{5, 4, 3, 2, 1} 176 | s := Uint64(data) 177 | s.Sort() 178 | result := s.Join(",") 179 | expected := "1,2,3,4,5" 180 | is2.Equal(expected, result) 181 | s.Clear() 182 | is2.Equal(s.Join(""), "") 183 | } 184 | -------------------------------------------------------------------------------- /uint8.go: -------------------------------------------------------------------------------- 1 | // Package slicer contains utility classes for handling slices 2 | package slicer 3 | 4 | // Imports 5 | import "sort" 6 | import "fmt" 7 | import "strings" 8 | 9 | // Uint8Slicer handles slices of uint8 10 | type Uint8Slicer struct { 11 | slice []uint8 12 | } 13 | 14 | // Uint8 creates a new Uint8Slicer 15 | func Uint8(slice ...[]uint8) *Uint8Slicer { 16 | if len(slice) > 0 { 17 | return &Uint8Slicer{slice: slice[0]} 18 | } 19 | return &Uint8Slicer{} 20 | } 21 | 22 | // Add a uint8 value to the slicer 23 | func (s *Uint8Slicer) Add(value uint8, additional ...uint8) { 24 | s.slice = append(s.slice, value) 25 | s.slice = append(s.slice, additional...) 26 | } 27 | 28 | // AddUnique adds a uint8 value to the slicer if it does not already exist 29 | func (s *Uint8Slicer) AddUnique(value uint8, additional ...uint8) { 30 | 31 | if !s.Contains(value) { 32 | s.slice = append(s.slice, value) 33 | } 34 | 35 | // Add additional values 36 | for _, value := range additional { 37 | if !s.Contains(value) { 38 | s.slice = append(s.slice, value) 39 | } 40 | } 41 | } 42 | 43 | // AddSlice adds a uint8 slice to the slicer 44 | func (s *Uint8Slicer) AddSlice(value []uint8) { 45 | s.slice = append(s.slice, value...) 46 | } 47 | 48 | // AsSlice returns the slice 49 | func (s *Uint8Slicer) AsSlice() []uint8 { 50 | return s.slice 51 | } 52 | 53 | // AddSlicer appends a Uint8Slicer to the slicer 54 | func (s *Uint8Slicer) AddSlicer(value *Uint8Slicer) { 55 | s.slice = append(s.slice, value.AsSlice()...) 56 | } 57 | 58 | // Filter the slice based on the given function 59 | func (s *Uint8Slicer) Filter(fn func(uint8) bool) *Uint8Slicer { 60 | result := &Uint8Slicer{} 61 | for _, elem := range s.slice { 62 | if fn(elem) { 63 | result.Add(elem) 64 | } 65 | } 66 | return result 67 | } 68 | 69 | // Each runs a function on every element of the slice 70 | func (s *Uint8Slicer) Each(fn func(uint8)) { 71 | for _, elem := range s.slice { 72 | fn(elem) 73 | } 74 | } 75 | 76 | // Contains indicates if the given value is in the slice 77 | func (s *Uint8Slicer) Contains(matcher uint8) bool { 78 | result := false 79 | for _, elem := range s.slice { 80 | if elem == matcher { 81 | result = true 82 | } 83 | } 84 | return result 85 | } 86 | 87 | // Length returns the number of elements in the slice 88 | func (s *Uint8Slicer) Length() int { 89 | return len(s.slice) 90 | } 91 | 92 | // Clear all elements in the slice 93 | func (s *Uint8Slicer) Clear() { 94 | s.slice = []uint8{} 95 | } 96 | 97 | // Deduplicate removes duplicate values from the slice 98 | func (s *Uint8Slicer) Deduplicate() { 99 | 100 | result := &Uint8Slicer{} 101 | 102 | for _, elem := range s.slice { 103 | if !result.Contains(elem) { 104 | result.Add(elem) 105 | } 106 | } 107 | 108 | s.slice = result.AsSlice() 109 | } 110 | 111 | // Join returns a string with the slicer elements separated by the given separator 112 | func (s *Uint8Slicer) Join(separator string) string { 113 | var builder strings.Builder 114 | 115 | // Shortcut no elements 116 | if len(s.slice) == 0 { 117 | return "" 118 | } 119 | 120 | // Iterate over length - 1 121 | index := 0 122 | for index = 0; index < len(s.slice)-1; index++ { 123 | builder.WriteString(fmt.Sprintf("%v%s", s.slice[index], separator)) 124 | } 125 | builder.WriteString(fmt.Sprintf("%v", s.slice[index])) 126 | result := builder.String() 127 | return result 128 | } 129 | 130 | // Sort the slice values 131 | func (s *Uint8Slicer) Sort() { 132 | sort.Slice(s.slice, func(i, j int) bool { return s.slice[i] < s.slice[j] }) 133 | } 134 | -------------------------------------------------------------------------------- /uint8_test.go: -------------------------------------------------------------------------------- 1 | package slicer 2 | 3 | import ( 4 | "github.com/matryer/is" 5 | "testing" 6 | ) 7 | 8 | func TestUint8Add(t *testing.T) { 9 | 10 | is2 := is.New(t) 11 | s := Uint8() 12 | s.Add(1) 13 | s.Add(2) 14 | 15 | is2.Equal(s.AsSlice(), []uint8{1, 2}) 16 | 17 | s.Clear() 18 | s.Add(1, 2) 19 | 20 | is2.Equal(s.AsSlice(), []uint8{1, 2}) 21 | 22 | } 23 | 24 | func TestUint8Length(t *testing.T) { 25 | is2 := is.New(t) 26 | s := Uint8() 27 | s.Add(1) 28 | s.Add(2) 29 | 30 | is2.Equal(s.Length(), 2) 31 | } 32 | 33 | func TestUint8AddUnique(t *testing.T) { 34 | is2 := is.New(t) 35 | s := Uint8() 36 | s.AddUnique(1) 37 | s.AddUnique(2) 38 | s.AddUnique(2) 39 | s.AddUnique(2) 40 | 41 | is2.Equal(s.AsSlice(), []uint8{1, 2}) 42 | 43 | s.Clear() 44 | s.AddUnique(1, 2, 1, 2, 2, 1) 45 | 46 | is2.Equal(s.AsSlice(), []uint8{1, 2}) 47 | } 48 | 49 | func TestUint8Deduplicate(t *testing.T) { 50 | is2 := is.New(t) 51 | s := Uint8() 52 | s.Add(1) 53 | s.Add(2) 54 | s.Add(2) 55 | s.Add(2) 56 | 57 | is2.Equal(s.Length(), 4) 58 | is2.Equal(s.AsSlice(), []uint8{1, 2, 2, 2}) 59 | s.Deduplicate() 60 | is2.Equal(s.Length(), 2) 61 | is2.Equal(s.AsSlice(), []uint8{1, 2}) 62 | } 63 | 64 | func TestUint8AddSlice(t *testing.T) { 65 | is2 := is.New(t) 66 | 67 | s := Uint8() 68 | s.Add(1) 69 | s.Add(2) 70 | 71 | extras := []uint8{3, 4} 72 | 73 | s.AddSlice(extras) 74 | is2.Equal(s.AsSlice(), []uint8{1, 2, 3, 4}) 75 | } 76 | 77 | func TestUint8AddSlicer(t *testing.T) { 78 | 79 | is2 := is.New(t) 80 | 81 | s := Uint8() 82 | s.Add(1) 83 | s.Add(2) 84 | 85 | p := Uint8() 86 | p.Add(3) 87 | p.Add(4) 88 | 89 | s.AddSlicer(p) 90 | 91 | is2.Equal(s.AsSlice(), []uint8{1, 2, 3, 4}) 92 | } 93 | 94 | func TestUint8Filter(t *testing.T) { 95 | 96 | is2 := is.New(t) 97 | s := Uint8() 98 | s.Add(18) 99 | s.Add(120) 100 | s.Add(1) 101 | s.Add(10) 102 | s.Add(20) 103 | s.Add(3) 104 | s.Add(29) 105 | 106 | result := s.Filter(func(i uint8) bool { 107 | return i > 19 108 | }) 109 | 110 | is2.Equal(result.AsSlice(), []uint8{120, 20, 29}) 111 | 112 | } 113 | 114 | func TestUint8Each(t *testing.T) { 115 | 116 | is2 := is.New(t) 117 | s := Uint8() 118 | s.Add(18) 119 | s.Add(10) 120 | s.Add(1) 121 | s.Add(10) 122 | s.Add(20) 123 | s.Add(3) 124 | s.Add(29) 125 | 126 | var result uint8 127 | 128 | s.Each(func(i uint8) { 129 | result = result + i 130 | }) 131 | var expected uint8 = 91 132 | is2.Equal(result, expected) 133 | } 134 | 135 | // TestOptionalUint8Slice tests when you construct a Uint8 with 136 | // an existing slice 137 | func TestOptionalUint8Slice(t *testing.T) { 138 | is2 := is.New(t) 139 | 140 | data := []uint8{1, 2, 3} 141 | s := Uint8(data) 142 | 143 | var result uint8 = 0 144 | s.Each(func(elem uint8) { 145 | result += elem 146 | }) 147 | var expected uint8 = 6 148 | is2.Equal(result, expected) 149 | 150 | } 151 | 152 | // TestUint8Sort tests that the slicer can be sorted 153 | func TestUint8Sort(t *testing.T) { 154 | is2 := is.New(t) 155 | 156 | data := []uint8{5, 4, 3, 2, 1} 157 | s := Uint8(data) 158 | s.Sort() 159 | result := s.Join(",") 160 | expected := "1,2,3,4,5" 161 | is2.Equal(result, expected) 162 | s.Clear() 163 | is2.Equal(s.Join(""), "") 164 | } 165 | -------------------------------------------------------------------------------- /uint_test.go: -------------------------------------------------------------------------------- 1 | package slicer 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/matryer/is" 6 | "testing" 7 | ) 8 | 9 | func TestUintAdd(t *testing.T) { 10 | 11 | s := Uint() 12 | s.Add(1) 13 | s.Add(2) 14 | 15 | expected := "[1,2]" 16 | actual, _ := json.Marshal(s.AsSlice()) 17 | if expected != string(actual) { 18 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 19 | } 20 | 21 | s.Clear() 22 | s.Add(1, 2) 23 | 24 | expected = "[1,2]" 25 | actual, _ = json.Marshal(s.AsSlice()) 26 | if expected != string(actual) { 27 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 28 | } 29 | } 30 | func TestUintDeduplicate(t *testing.T) { 31 | is2 := is.New(t) 32 | s := Uint() 33 | s.Add(1) 34 | s.Add(2) 35 | s.Add(2) 36 | s.Add(2) 37 | 38 | is2.Equal(s.Length(), 4) 39 | is2.Equal(s.AsSlice(), []uint{1, 2, 2, 2}) 40 | s.Deduplicate() 41 | is2.Equal(s.Length(), 2) 42 | is2.Equal(s.AsSlice(), []uint{1, 2}) 43 | } 44 | 45 | func TestUintLength(t *testing.T) { 46 | is2 := is.New(t) 47 | s := Uint() 48 | s.Add(1) 49 | s.Add(2) 50 | 51 | is2.Equal(s.Length(), 2) 52 | } 53 | 54 | func TestUintAddUnique(t *testing.T) { 55 | 56 | s := Uint() 57 | s.AddUnique(1) 58 | s.AddUnique(2) 59 | s.AddUnique(2) 60 | s.AddUnique(2) 61 | 62 | expected := "[1,2]" 63 | actual, _ := json.Marshal(s.AsSlice()) 64 | if expected != string(actual) { 65 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 66 | } 67 | 68 | s.Clear() 69 | s.AddUnique(1, 2, 1, 2, 2, 1) 70 | 71 | expected = "[1,2]" 72 | actual, _ = json.Marshal(s.AsSlice()) 73 | if expected != string(actual) { 74 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 75 | } 76 | } 77 | 78 | func TestUintAddSlice(t *testing.T) { 79 | 80 | s := Uint() 81 | s.Add(1) 82 | s.Add(2) 83 | 84 | extras := []uint{3, 4} 85 | 86 | s.AddSlice(extras) 87 | 88 | expected := "[1,2,3,4]" 89 | actual, _ := json.Marshal(s.AsSlice()) 90 | if expected != string(actual) { 91 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 92 | } 93 | } 94 | 95 | func TestUintAddSlicer(t *testing.T) { 96 | 97 | s := Uint() 98 | s.Add(1) 99 | s.Add(2) 100 | 101 | p := Uint() 102 | p.Add(3) 103 | p.Add(4) 104 | 105 | s.AddSlicer(p) 106 | 107 | expected := "[1,2,3,4]" 108 | actual, _ := json.Marshal(s.AsSlice()) 109 | if expected != string(actual) { 110 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 111 | } 112 | } 113 | 114 | func TestUintFilter(t *testing.T) { 115 | 116 | s := Uint() 117 | s.Add(18) 118 | s.Add(120) 119 | s.Add(1) 120 | s.Add(10) 121 | s.Add(20) 122 | s.Add(3) 123 | s.Add(29) 124 | 125 | result := s.Filter(func(i uint) bool { 126 | return i > 19 127 | }) 128 | 129 | expected := "[120,20,29]" 130 | actual, _ := json.Marshal(result.AsSlice()) 131 | if expected != string(actual) { 132 | t.Errorf("Expected '%s', but got '%s'", expected, actual) 133 | } 134 | } 135 | 136 | // TestOptionalUintSlice tests when you construct a Uint with 137 | // an existing slice 138 | func TestOptionalUintSlice(t *testing.T) { 139 | data := []uint{1, 2, 3} 140 | s := Uint(data) 141 | 142 | var result uint = 0 143 | s.Each(func(elem uint) { 144 | result += elem 145 | }) 146 | var expected uint = 6 147 | if expected != result { 148 | t.Errorf("Expected '%d', but got '%d'", expected, result) 149 | } 150 | } 151 | 152 | // TestUintSort tests that the slicer can be sorted 153 | func TestUintSort(t *testing.T) { 154 | is2 := is.New(t) 155 | data := []uint{5, 4, 3, 2, 1} 156 | s := Uint(data) 157 | s.Sort() 158 | result := s.Join(",") 159 | expected := "1,2,3,4,5" 160 | is2.Equal(expected, result) 161 | s.Clear() 162 | is2.Equal(s.Join(""), "") 163 | } 164 | --------------------------------------------------------------------------------