├── .gitignore ├── .travis.yml ├── CONTRIBUTING.md ├── LICENSE ├── Makefile ├── README.md ├── build ├── examples ├── number_examples.go ├── player_examples │ ├── main.go │ └── player │ │ ├── Players_hasgo.go │ │ └── player.go └── project_euler_1.go ├── functions ├── abs.go ├── all.go ├── any.go ├── average.go ├── break.go ├── delete.go ├── drop.go ├── dropwhile.go ├── elem.go ├── filter.go ├── foldl.go ├── foldl1.go ├── foldr.go ├── foldr1.go ├── go.mod ├── group.go ├── head.go ├── init.go ├── inits.go ├── intercalate.go ├── intersperse.go ├── isprefixof.go ├── last.go ├── length.go ├── main.go ├── map.go ├── maximum.go ├── maximumby.go ├── minimum.go ├── modes.go ├── nub.go ├── null.go ├── product.go ├── reverse.go ├── scanl.go ├── sort.go ├── span.go ├── splitat.go ├── sum.go ├── tail.go ├── tails.go ├── take.go ├── takewhile.go ├── uncons.go ├── unlines.go └── unwords.go ├── generator.go ├── go.mod ├── go.sum ├── hasgo.go ├── template.go └── types ├── Bools.go ├── Bools_test.go ├── Ints.go ├── Ints_hasgo.go ├── Ints_test.go ├── Person.go ├── Persons_test.go ├── Strings.go ├── Strings_hasgo.go ├── Strings_test.go ├── go.mod └── persons_hasgo.go /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | 3 | # swap 4 | [._]*.s[a-w][a-z] 5 | [._]s[a-w][a-z] 6 | # session 7 | Session.vim 8 | # temporary 9 | .netrwhist 10 | *~ 11 | # auto-generated tag files 12 | tags 13 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - "1.13" 5 | - "1.14" 6 | - "1.15" 7 | - "1.16" 8 | 9 | script: 10 | - go get golang.org/x/tools/go/packages 11 | - cd types && go test ./... 12 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribution guidelines 2 | 3 | ## Contributing functions 4 | 5 | Imagine you have a new function idea, let's call it Init. These are the steps you'd need to follow 6 | to get a PR merged. 7 | 8 | * Create Init.go under `/functions` 9 | * Write the code for your function (the fun part!) 10 | * Add your function in `functions/main.go` and specify for which types it applies 11 | * ForNumbers, ForStrings, ForStructs, ... 12 | * Try to generate your code for the built-in types by running the python build script 13 | * ./build 14 | * Write the respective unit tests in `types/*_test.go` 15 | 16 | That's it! If everything went well you now have a PR ready for including your function in Hasgo. 17 | 18 | If you need some inspiration, check out the issues and pick one to start contributing. Feel free to 19 | suggest a new function as well, but it's a good idea to first create the issue before you start 20 | coding so we can help you get started in a good way! 21 | 22 | If you get stuck, just create the PR of what you have and we'll help get you through the steps 23 | :smiley: 24 | 25 | Happy Coding! :raised_hands: 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Dylan Meeus 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 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | target: ; 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hasgo [![Mentioned in Awesome Go](https://awesome.re/mentioned-badge.svg)](https://github.com/avelino/awesome-go) [![Build Status](https://travis-ci.com/DylanMeeus/hasgo.svg?branch=master)](https://travis-ci.com/DylanMeeus/hasgo) 2 | * Coverage status: [gocover.io](https://gocover.io/github.com/DylanMeeus/hasgo/types) 3 | * Our report card: [![Go Report Card](https://goreportcard.com/badge/github.com/DylanMeeus/hasgo)](https://goreportcard.com/report/github.com/DylanMeeus/hasgo) 4 | 5 | Hasgo is a code generator with functions influenced by Haskell. 6 | It comes with some types out-of-the-box so you can start using it without running the generator. 7 | Specifically you can start using Hasgo's `Strings` and `Ints` types. 8 | 9 | We want to focus on being: 10 | * Immutable 11 | * Strongly-Typed (no `interface{}`) 12 | * Nil-safe 13 | 14 | 15 | ## Pie 16 | 17 | The inspiration for Hasgo, as well as some ideas around implementation come from the lovely [Pie 18 | library](https://github.com/elliotchance/pie), made by [Elliot Chance](https://github.com/elliotchance). 19 | It's safe to say that Hasgo would not exist without Pie. However, the way Pie and Hasgo work is not 20 | the same and neither is the focus of the project. If you don't find a function in Hasgo, check out 21 | Pie! :smiley: 22 | 23 | ## Example 24 | 25 | ```go 26 | import . "github.com/DylanMeeus/hasgo/types" 27 | func EpicFunction() { 28 | // create a range of -10 -> 10. Take the absolute values, keep only even numbers, and sum them. 29 | result := IntRange(-10,10). 30 | Abs(). 31 | Filter(func(i int64) bool { 32 | return i % 2 == 0 33 | }). 34 | Sum() 35 | // result = 60 36 | } 37 | ``` 38 | 39 | You can find more [examples here](https://github.com/DylanMeeus/hasgo/tree/master/examples). 40 | 41 | ## Installation 42 | 43 | ```bash 44 | go get -u github.com/DylanMeeus/hasgo 45 | ``` 46 | 47 | Or add hasgo to your `go.mod` file. 48 | 49 | `require github.com/DylanMeeus/hasgo/v1.0.2` 50 | 51 | ## Types 52 | * `Ints` ([]int64) 53 | * `Strings` ([]string) 54 | 55 | ## Functions 56 | 57 | These are the function currently available with Hasgo. 58 | It shows you which type of data they operate on as well as the Haskell type definition. 59 | The first symbol of the signature is actually the method receiver in Go terms. 60 | 61 | Alternatively, you can consult the [godoc](https://godoc.org/github.com/DylanMeeus/hasgo/types) 62 | 63 | ### Generic functions 64 | These functions can be generated for every type. 65 | 66 | | Function | Signature | String | Number | Struct | Description | 67 | |------------ | ------------------------------- | :----: | :----: | :----: | ----------- | 68 | | `Abs` | `[a] -> [a]` | | ✓ | | Return a slice containing the absolute values| 69 | | `All` | `[a] -> (a -> bool) -> bool` | ✓ | ✓ | ✓ | Returns true if the predicate applies to all elements in the slice| 70 | | `Any` | `[a] -> (a -> bool) -> bool` | ✓ | ✓ | ✓ | Returns true if one or more elements satisfy the predicate| 71 | | `Average` | `[a] -> a` | | ✓ | | Returns the average of all elements| 72 | | `Break` | `(a -> bool) -> [a] -> ([a], [a])`| ✓ | ✓ | ✓ | Returns a tuple of all elements until the first one that matches the predicate, followed by the remaining elements. | 73 | | `Delete` | `[a] -> a -> [a]` | ✓ | ✓ | ✓ | Returns the slice with the first occurance of the element deleted.| 74 | | `Drop` | `Int -> [a] -> [a]` | ✓ | ✓ | ✓ | Returns the suffix of xs after the first n elements. | 75 | | `DropWhile` | `(a -> bool) -> [a] -> [a]` | ✓ | ✓ | ✓ | Returns the suffix of xs after the predicate's first failure. | 76 | | `Elem` | `[a] -> a -> bool` | ✓ | ✓ | ✓ | Returns true if the slice contains the element.| 77 | | `Filter` | `[a] -> (a -> bool) -> [a]` | ✓ | ✓ | ✓ | Filter the slice based on a predicate| 78 | | `Foldl` | `[a] -> a -> (a -> a -> a) -> a` | ✓ | ✓ | ✓ | Left fold over the slice to reduce it to one element with starting value.| 79 | | `Foldl1` | `[a] -> (a -> a -> a) -> a` | ✓ | ✓ | ✓ | Left fold over the slice to reduce it to one element.| 80 | | `Foldr` | `[a] -> b -> (a -> b -> b) -> b` | ✓ | ✓ | ✓ | Right fold over the slice to reduce it to one element with a starting value. | 81 | | `Foldr1` | `[a] -> (a -> a -> a) -> a` | ✓ | ✓ | ✓ | Right fold over the slice to reduce it to one element. | 82 | | `Group` | `[a] -> [[a]]` | ✓ | ✓ | ✓ | Returns a list of lists where each list contains grouped values from the input list.| 83 | | `Head` | `[a] -> a` | ✓ | ✓ | ✓ | Return the first element| 84 | | `Init` | `[a] -> [a]` | ✓ | ✓ | ✓ | Returns all elements minus the last| 85 | | `Inits` | `[a] -> [[a]]` | ✓ | ✓ | ✓ | Returns all initial segments of the slice, shortest first. | 86 | | `Intercalate`| `[a] -> [[a]] -> [a]` | ✓ | ✓ | ✓ | Intersperses the slice in between the provided 2d-slice | 87 | | `Intersperse`| `[a] -> a -> [a]` | ✓ | ✓ | ✓ | Intersperses the value in between all elements of the provided slice| 88 | | `IsPrefixOf` | `[a] -> [a] -> bool` | ✓ | ✓ | ✓ | Returns true if the current slice is a prefix of the provided slice| 89 | | `Last` | `[a] -> a` | ✓ | ✓ | ✓ | Returns the last element| 90 | | `Length` | `[a] -> int` | ✓ | ✓ | ✓ | Returns the length of the slice| 91 | | `Map` | `[a] -> (a -> a) -> [a]` | ✓ | ✓ | ✓ | Returns a slice with the function applied to each element of the input| 92 | | `Maximum` | `[a] -> a` | | ✓ | | Returns the largest element| 93 | | `MaximumBy` | `[a] -> (a -> a) -> a -> a` | ✓ | ✓ | ✓ | Returns the maximum element according to comparator| 94 | | `Minimum` | `[a] -> a` | | ✓ | | Returns the lowest element| 95 | | `Modes` | `[a] -> [a]` | ✓ | ✓ | ✓ | Returns the elements with the highest frequency | 96 | | `Nub` | `[a] -> [a]` | ✓ | ✓ | ✓ | Returns a Slice containing one of each of the input elements | 97 | | `Null` | `[a] -> bool` | ✓ | ✓ | ✓ | Returns true if the slice is empty, false otherwise| 98 | | `Product` | `[a] -> a` | ✓ | | | Returns the product of all elements in the slice.| 99 | | `Reverse` | `[a] -> [a]` | ✓ | ✓ | ✓ | Returns a slice with the elements reversed| 100 | | `Scanl` | `[a] -> b -> (a -> b -> a) -> [b]`| ✓ | ✓ | ✓ | Left fold over the slice to reduce it to one element with a starting value and return every iteration in a slice. | 101 | | `Sort` | `[a] -> [a]` | ✓ | ✓ | | Returns a sorted slice (original remains unsorted)| 102 | | `Span` | `(a -> bool) -> [a] -> ([a], [a])`| ✓ | ✓ | ✓ | Returns a tuple of all elements until the first one that does not match the predicate, followed by the remaining elements. | 103 | | `SplitAt` | `Int -> [a] -> ([a], [a])` | ✓ | ✓ | ✓ | Returns a tuple with all elements up until the specified index, followed by the elements after the index. | 104 | | `Sum` | `[a] -> a` | ✓ | ✓ | ✓ | The sum of elements in the slice| 105 | | `Tail` | `[a] -> [a]` | ✓ | ✓ | ✓ | Returns all elements minus the first| 106 | | `Tails` | `[a] -> [[a]]` | ✓ | ✓ | ✓ | Returns all final segments of the slice, longest first. | 107 | | `Take` | `[a] -> uint64 -> [a]` | ✓ | ✓ | ✓ | Take N elements from the slice, or all if N exceeds the length.| 108 | | `TakeWhile` | `[a] -> (a -> bool) -> [a]` | ✓ | ✓ | ✓ | Take all elements until the first one that does not match the predicate.| 109 | | `Uncons` | `[a] -> (a, [a])` | ✓ | ✓ | ✓ | Returns a tuple of the head and tail of the slice| 110 | | `Unlines` | `[a] -> string` | ✓ | ✓ | ✓ | Returns a newline separated string of all elements in the slice| 111 | | `Unwords` | `[a] -> string` | ✓ | ✓ | ✓ | Returns a space-separated string of all elements in the slice| 112 | 113 | 114 | ### Hardcoded functions 115 | 116 | The built-in types (Strings, Ints, Bools) have some functions defined on them that are not generated. 117 | Mostly because we could not create them in a generic way. 118 | 119 | 120 | | Type | Function | Signature | Description | 121 | |--------- |--------------- |-------------------------------|--------------| 122 | | `Ints` | `Equals` | \*`Ints -> Ints -> bool` | Returns true if both slices contain the same elements| 123 | | `Ints` | `EqualsOrdered` | \*`Ints -> Ints -> bool` | Returns true if both slices contain the same elements, in the same position| 124 | | `Ints` | `IntRange` | `int64 -> int64 -> Ints` | Return an integer range from [start,stop]| 125 | | `Ints` | `IntReplicate` | `uint64 -> int64 -> Ints` | Return a slice with the input element repeated n times| 126 | | `Strings`| `Equals` | \*`Strings -> Strings -> bool`| Returns true if both slices contain the same elements| 127 | | `Strings`| `EqualsOrdered` | \*`Strings -> Strings -> bool`| Returns true if both slices contain the same elements, in the same position| 128 | | `Strings`| `Lines` | `string -> Strings` | Returns Strings separated by a newline.| 129 | | `Strings`| `StringReplicate`| `uint64 -> string -> Strings` | Return a slice with the input element repeated n times| 130 | | `Strings`| `Words` | `string -> Strings` | Returns Strings separated by a space.| 131 | | `Bools` | `And` | `Bools -> bool` | Returns true if all bools are true.| 132 | | `Bools` | `Or` | `Bools -> bool ` | Returns true if any bool is true.| 133 | 134 | \* (Functions prefixed by a star are functions added to the type itself, where first element in the 135 | signature is the method receiver. So for examples, the Equals method is `Ints{1,2}.Equals(Ints{1})`. 136 | But, the IntRange function looks like `hasgo.IntRange(0,10)`. 137 | 138 | 139 | ## Contributing 140 | 141 | You can help out Hasgo in a variety of ways! 142 | Here are some ideas: 143 | 144 | * Use Hasgo! :smiley: 145 | * Spread the word (Write a blog, tweet, talk about..) 146 | * Suggest features (Create an issue to make a suggestion) 147 | * Report bugs (Similarly, create an issue) 148 | * Contribute code. (Create a PR, we'll gladly take a look and help you get it merged!) 149 | * We have separate [contribution guidelines](CONTRIBUTING.md) 150 | 151 | ## What's in a name? 152 | The name Hasgo is a portmanteau of "Haskell" and "Go". I'm a big fan of both languages, though they 153 | are quite different. It's impossible to write real Haskell-like code in Go. There are some obvious 154 | differences between the languages in terms of syntax. I hope the functions in this library stay as 155 | close as possible to their Haskell implementations. There might be extra functions in here that are 156 | not in Haskell, and there _will_ be functions in Haskell that you won't find here. 157 | 158 | The inspiration mainly shows in the naming of functions. If the functions were named after Java 159 | lambdas, it'd be called "Jago". Sorry if you expected more Haskell goodness (I'm open to suggestions 160 | of how more haskell in Hasgo!) 161 | 162 | ## Real Generics? 163 | 164 | Currently I have an experimental implementation of hasgo [here as hasgo2](https://www.github.com/DylanMeeus/hasgo2). It does require a development version of Go installed from source to function correctly at this stage. 165 | 166 | -------------------------------------------------------------------------------- /build: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | 4 | print("Generating the templates..") 5 | os.system("go run generator.go") 6 | print("Clearing existing files") 7 | os.system("cd types && rm ./*_hasgo*") 8 | print("updating modules..") 9 | os.system("go mod tidy") 10 | print("Installing new Hasgo lib") 11 | os.system("go install") 12 | print("Generating source files...") 13 | os.system("cd types && go generate ./...") 14 | print("Formatting files..") 15 | os.system("gofmt -s -w .") 16 | print("Running unit tests") 17 | os.system("cd types/ && go test ./... && cd -") 18 | print("Running go lint..") 19 | os.system("golint ./...") 20 | -------------------------------------------------------------------------------- /examples/number_examples.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | hasgo "github.com/DylanMeeus/hasgo/types" 6 | ) 7 | 8 | // these are just examples, not the way you'd actually implement them in Go. 9 | 10 | func main() { 11 | fmt.Printf("product: %v\n", Multiply(1, hasgo.Ints{1, 2, 3})) 12 | EpicFunction() 13 | fmt.Printf("fold %v\n", fold()) 14 | } 15 | 16 | // EpicFunction is a simple example as seen on the github homepage. 17 | func EpicFunction() { 18 | result := hasgo.IntRange(-10, 10). 19 | Abs(). 20 | Filter(func(i int64) bool { 21 | return i%2 == 0 22 | }). 23 | Sum() 24 | fmt.Printf("%v\n", result) 25 | } 26 | 27 | // Multiply implements a recursively multiplier 28 | func Multiply(product int64, numbers hasgo.Ints) int64 { 29 | if len(numbers) == 0 { 30 | return product 31 | } 32 | h, rest := numbers.Uncons() 33 | return Multiply(product*h, rest) 34 | } 35 | 36 | func fold() int64 { 37 | result := hasgo.IntRange(0, 10). 38 | Foldr(0, func(i1, i2 int64) int64 { return i1 - i2 }) 39 | return result 40 | 41 | } 42 | -------------------------------------------------------------------------------- /examples/player_examples/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | } 5 | -------------------------------------------------------------------------------- /examples/player_examples/player/Players_hasgo.go: -------------------------------------------------------------------------------- 1 | // Package player contains code generated by hasgo. [DO NOT EDIT!] 2 | package player 3 | 4 | import ( 5 | "fmt" 6 | ) 7 | 8 | // =============== all.go ================= 9 | 10 | // All returns true if all elements of the slice satisfy the predicate. 11 | // Can be generated for any type. 12 | func (s Players) All(f func(Player) bool) bool { 13 | if f == nil { 14 | return false 15 | } 16 | for _, v := range s { 17 | if !f(v) { 18 | return false 19 | } 20 | } 21 | return true 22 | } 23 | 24 | // =============== any.go ================= 25 | 26 | // Any returns true if any of the elements satisfy the predicate. 27 | // Can be generated for any type. 28 | func (s Players) Any(f func(Player) bool) bool { 29 | if f == nil { 30 | return false 31 | } 32 | for _, v := range s { 33 | if f(v) { 34 | return true 35 | } 36 | } 37 | return false 38 | } 39 | 40 | // =============== delete.go ================= 41 | 42 | // Delete returns a slice with the first matching element 43 | // removed from the slice. 44 | // Can be generated for any type. 45 | func (s Players) Delete(e Player) (out Players) { 46 | deleted := false 47 | for _, v := range s { 48 | if deleted || v != e { 49 | out = append(out, v) 50 | } else { 51 | deleted = true 52 | } 53 | } 54 | return 55 | } 56 | 57 | // =============== drop.go ================= 58 | 59 | // Drop returns a new Slice with the elements after the provided key. 60 | // Can be generated for any type. 61 | func (s Players) Drop(i int) (out Players) { 62 | for i < len(s) { 63 | out = append(out, s[i]) 64 | i++ 65 | } 66 | return 67 | } 68 | 69 | // =============== dropwhile.go ================= 70 | 71 | // DropWhile returns a new slice containing all elements after the predicate fails for the first time. 72 | // Can be generated for any type. 73 | func (s Players) DropWhile(f func(Player) bool) (out Players) { 74 | if f == nil { 75 | return s 76 | } 77 | failed := false 78 | for _, v := range s { 79 | if failed { 80 | out = append(out, v) 81 | continue 82 | } 83 | if !f(v) { 84 | out = append(out, v) 85 | failed = true 86 | } 87 | } 88 | return 89 | } 90 | 91 | // =============== elem.go ================= 92 | 93 | // Elem returns true if the slice contains the element 94 | // Can be generated for any type. 95 | func (s Players) Elem(el Player) bool { 96 | for _, e := range s { 97 | if e == el { 98 | return true 99 | } 100 | } 101 | return false 102 | } 103 | 104 | // =============== filter.go ================= 105 | 106 | // Filter returns a slice containing only the elements that match the predicate. 107 | // Can be generated for any type. 108 | func (s Players) Filter(f func(Player) bool) (out Players) { 109 | for _, v := range s { 110 | if f(v) { 111 | out = append(out, v) 112 | } 113 | } 114 | return 115 | } 116 | 117 | // =============== foldl.go ================= 118 | 119 | // Foldl reduces a list by iteratively applying f from left->right. Thus, for an empty slice, the result is the default zero-value. 120 | func (s Players) Foldl(z Player, f func(e1, e2 Player) Player) (out Player) { 121 | if len(s) == 0 { 122 | return 123 | } 124 | out = s[0] 125 | for _, v := range s[1:] { 126 | out = f(out, v) 127 | } 128 | return f(out, z) 129 | } 130 | 131 | // =============== foldl1.go ================= 132 | 133 | // Foldl1 reduces a list by iteratively applying f from left->right. Thus, for an empty slice, the result is the default zero-value. 134 | func (s Players) Foldl1(f func(e1, e2 Player) Player) (out Player) { 135 | if len(s) == 0 { 136 | return 137 | } 138 | out = s[0] 139 | for _, v := range s[1:] { 140 | out = f(out, v) 141 | } 142 | return 143 | } 144 | 145 | // =============== head.go ================= 146 | 147 | // Head returns the first element in the slice. 148 | // If no element is found, returns the zero-value of the type. 149 | // Can be generated for any type. 150 | func (s Players) Head() (out Player) { 151 | if len(s) > 0 { 152 | out = s[0] 153 | } 154 | return 155 | } 156 | 157 | // =============== init.go ================= 158 | 159 | // Init takes n-1 elements from a slice, where n = len(list). 160 | // Can be generated for any type. 161 | func (s Players) Init() (out Players) { 162 | if len(s) == 0 { 163 | return 164 | } 165 | slicecopy := append([]Player(nil), s...) 166 | return slicecopy[:len(s)-1] 167 | } 168 | 169 | // =============== intercalate.go ================= 170 | 171 | // Intercalate inserts the method receiver slice into the function slice at each step. 172 | // Can be generated for any type. 173 | func (s Players) Intercalate(ss [][]Player) (out Players) { 174 | for i, slice := range ss { 175 | for _, el := range slice { 176 | out = append(out, el) 177 | } 178 | if i == len(ss)-1 { 179 | break 180 | } 181 | for _, el := range s { 182 | out = append(out, el) 183 | } 184 | } 185 | return out 186 | } 187 | 188 | // =============== intersperse.go ================= 189 | 190 | // Intersperse inserts the receiving value between each element of the method receiver. 191 | // Can be generated for any type. 192 | func (s Players) Intersperse(value Player) (out Players) { 193 | for i, el := range s { 194 | out = append(out, el) 195 | if i == len(s)-1 { 196 | break 197 | } 198 | out = append(out, value) 199 | } 200 | return 201 | } 202 | 203 | // =============== last.go ================= 204 | 205 | // Last returns the last element in the slice 206 | // If no element is found, returns the zero-value of the type 207 | // Can be generated for any type. 208 | func (s Players) Last() (out Player) { 209 | if len(s) > 0 { 210 | out = s[len(s)-1] 211 | } 212 | return 213 | } 214 | 215 | // =============== length.go ================= 216 | 217 | // Length returns the length (len) of a slice. 218 | // Can be generated for any type. 219 | func (s Players) Length() int { 220 | return len(s) 221 | } 222 | 223 | // =============== map.go ================= 224 | 225 | // Map return a new slice with the map operation applied to each element. 226 | // Can be generated for any type. 227 | func (s Players) Map(f func(Player) Player) (out Players) { 228 | if f == nil { 229 | return s 230 | } 231 | for _, v := range s { 232 | out = append(out, f(v)) 233 | } 234 | return 235 | } 236 | 237 | // =============== maximumby.go ================= 238 | 239 | // MaximumBy returns the maximum elements according to a custom comparator. 240 | // Can be generated for any type. 241 | func (s Players) MaximumBy(f func(e1, e2 Player) Player) (max Player) { 242 | if len(s) == 0 { 243 | return 244 | } 245 | max = s[0] 246 | for _, el := range s[1:] { 247 | max = f(max, el) 248 | } 249 | return 250 | } 251 | 252 | // =============== modes.go ================= 253 | 254 | // Modes returns the elements with highest frequency in the slice. 255 | // Can be generated for any type. 256 | func (s Players) Modes() (out Players) { 257 | if len(s) == 0 { 258 | return 259 | } 260 | 261 | counts := make(map[Player]int) 262 | for _, v := range s { 263 | counts[v]++ 264 | } 265 | 266 | var max int 267 | for _, v := range counts { 268 | if v > max { 269 | max = v 270 | } 271 | } 272 | 273 | for k, v := range counts { 274 | if v == max { 275 | out = append(out, k) 276 | } 277 | } 278 | 279 | return 280 | } 281 | 282 | // =============== nub.go ================= 283 | 284 | // Nub returns a slice containing only the unique elements of the receiver. 285 | // The order of the elements is preserved. 286 | // Can be generated for any type. 287 | func (s Players) Nub() (out Players) { 288 | if len(s) == 0 { 289 | return 290 | } 291 | 292 | contains := make(map[Player]struct{}) 293 | for _, v := range s { 294 | if _, ok := contains[v]; !ok { 295 | contains[v] = struct{}{} 296 | out = append(out, v) 297 | } 298 | } 299 | return 300 | } 301 | 302 | // =============== null.go ================= 303 | 304 | // Null returns true the slice is empty. 305 | // Can be generated for any type. 306 | func (s Players) Null() bool { 307 | return len(s) == 0 308 | } 309 | 310 | // =============== reverse.go ================= 311 | 312 | // Reverse returns the reversed slice. 313 | // Can be generated for any type. 314 | func (s Players) Reverse() (out Players) { 315 | for i := len(s) - 1; i >= 0; i-- { 316 | out = append(out, s[i]) 317 | } 318 | return 319 | } 320 | 321 | // =============== tail.go ================= 322 | 323 | // Tail takes [1 -> n] elements from a slice, where n = len(list) 324 | // Returns an empty slice if there are less than 2 elements in slice 325 | // Can be generated for any type. 326 | func (s Players) Tail() (out Players) { 327 | if len(s) <= 1 { 328 | return 329 | } 330 | slicecopy := append([]Player(nil), s...) 331 | return slicecopy[1:] 332 | } 333 | 334 | // =============== take.go ================= 335 | 336 | // Take takes the first n elements of the slice, or the entire slice if n > len(slice). 337 | // Can be generated for any type. 338 | func (s Players) Take(n uint64) (out Players) { 339 | if len(s) == 0 { 340 | return 341 | } 342 | out = make(Players, len(s)) 343 | copy(out, s) 344 | if n < uint64(len(s)) { 345 | return out[:n] 346 | } 347 | return 348 | } 349 | 350 | // =============== takewhile.go ================= 351 | 352 | // TakeWhile continues appending to the output as long as the predicate is satisfied. 353 | // Can be generated for any type. 354 | func (s Players) TakeWhile(p func(Player) bool) (out Players) { 355 | if len(s) == 0 { 356 | return 357 | } 358 | for _, e := range s { 359 | if !p(e) { 360 | return 361 | } 362 | out = append(out, e) 363 | } 364 | return 365 | } 366 | 367 | // =============== uncons.go ================= 368 | 369 | // Uncons decomposes a slice into the head and tail component. 370 | // Can be generated for any type. 371 | func (s Players) Uncons() (head Player, tail Players) { 372 | return s.Head(), s.Tail() 373 | } 374 | 375 | // =============== unlines.go ================= 376 | 377 | // Unlines joins together the string representation of the slice with newlines after each element. 378 | // Can be generated for any type. 379 | func (s Players) Unlines() (out string) { 380 | for i, v := range s { 381 | out += fmt.Sprintf("%v", v) 382 | if i != len(s)-1 { 383 | out += "\n" 384 | } 385 | } 386 | return 387 | } 388 | 389 | // =============== unwords.go ================= 390 | 391 | // Unwords joins together the string representation of the slice with newlines after each element. 392 | // Can be generated for any type. 393 | func (s Players) Unwords() (out string) { 394 | for i, v := range s { 395 | out += fmt.Sprintf("%v", v) 396 | if i != len(s)-1 { 397 | out += " " 398 | } 399 | } 400 | return 401 | } 402 | -------------------------------------------------------------------------------- /examples/player_examples/player/player.go: -------------------------------------------------------------------------------- 1 | package player 2 | 3 | // Player represents a person in an online game. 4 | type Player struct { 5 | Nick string 6 | Score int 7 | } 8 | 9 | // Players is a wrapper for the []Player slice. 10 | // go:generate hasgo -T=Player -S=Players 11 | type Players []Player 12 | -------------------------------------------------------------------------------- /examples/project_euler_1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | hasgo "github.com/DylanMeeus/hasgo/types" 6 | ) 7 | 8 | func main() { 9 | hasgoFlavour() 10 | vanillaGo() 11 | } 12 | 13 | // The hasgo way of solving this problem 14 | func hasgoFlavour() { 15 | result := hasgo.IntRange(0, 1000).Filter(func(i int64) bool { 16 | return i%3 == 0 || i%5 == 0 17 | }).Sum() 18 | fmt.Printf("%v\n", result) 19 | } 20 | 21 | // this is how you could solve this in normal Go code. 22 | func vanillaGo() { 23 | var sum int 24 | for i := 0; i < 1000; i++ { 25 | if i%3 == 0 || i%5 == 0 { 26 | sum += i 27 | } 28 | } 29 | fmt.Printf("%v\n", sum) 30 | } 31 | -------------------------------------------------------------------------------- /functions/abs.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | import ( 4 | "math" 5 | ) 6 | 7 | // Abs returns the absolute value of all elements in the slice. 8 | // Can be generated for number-types. 9 | func (s SliceType) Abs() (out SliceType) { 10 | for _, v := range s { 11 | out = append(out, ElementType(math.Abs(float64(v)))) 12 | } 13 | return 14 | } 15 | -------------------------------------------------------------------------------- /functions/all.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | // All returns true if all elements of the slice satisfy the predicate. 4 | // Can be generated for any type. 5 | func (s SliceType) All(f func(ElementType) bool) bool { 6 | if len(s) == 0 { 7 | return true 8 | } 9 | if f == nil { 10 | return false 11 | } 12 | for _, v := range s { 13 | if !f(v) { 14 | return false 15 | } 16 | } 17 | return true 18 | } 19 | -------------------------------------------------------------------------------- /functions/any.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | // Any returns true if any of the elements satisfy the predicate. 4 | // Can be generated for any type. 5 | func (s SliceType) Any(f func(ElementType) bool) bool { 6 | if f == nil { 7 | return false 8 | } 9 | for _, v := range s { 10 | if f(v) { 11 | return true 12 | } 13 | } 14 | return false 15 | } 16 | -------------------------------------------------------------------------------- /functions/average.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | // Average returns the average of all elements in the slice. 4 | // Can be generated for all number types. 5 | func (s SliceType) Average() float64 { 6 | var sum ElementType 7 | if len(s) == 0 { 8 | return float64(0) 9 | } 10 | for _, i := range s { 11 | sum += i 12 | } 13 | return float64(sum) / float64(len(s)) 14 | } 15 | -------------------------------------------------------------------------------- /functions/break.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | // Break returns a tuple of any elements that do not satisfy the predicate up until the first time it passes, followed 4 | // by the rest of the elements. 5 | // Can be generated on any type. 6 | func (s SliceType) Break(f func(ElementType) bool) (before SliceType, after SliceType) { 7 | if f == nil { 8 | return before, s 9 | } 10 | 11 | passed := false 12 | 13 | for _, v := range s { 14 | if passed || f(v) { 15 | after = append(after, v) 16 | passed = true 17 | } else { 18 | before = append(before, v) 19 | } 20 | } 21 | 22 | return 23 | } 24 | -------------------------------------------------------------------------------- /functions/delete.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | // Delete returns a slice with the first matching element 4 | // removed from the slice. 5 | // Can be generated for any type. 6 | func (s SliceType) Delete(e ElementType) (out SliceType) { 7 | deleted := false 8 | for _, v := range s { 9 | if deleted || v != e { 10 | out = append(out, v) 11 | } else { 12 | deleted = true 13 | } 14 | } 15 | return 16 | } 17 | -------------------------------------------------------------------------------- /functions/drop.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | // Drop returns a new Slice with the elements after the provided key. 4 | // Can be generated for any type. 5 | func (s SliceType) Drop(i int) (out SliceType) { 6 | for i < len(s) { 7 | out = append(out, s[i]) 8 | i++ 9 | } 10 | return 11 | } 12 | -------------------------------------------------------------------------------- /functions/dropwhile.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | // DropWhile returns a new slice containing all elements after the predicate fails for the first time. 4 | // Can be generated for any type. 5 | func (s SliceType) DropWhile(f func(ElementType) bool) (out SliceType) { 6 | if f == nil { 7 | return s 8 | } 9 | failed := false 10 | for _, v := range s { 11 | if failed { 12 | out = append(out, v) 13 | continue 14 | } 15 | if !f(v) { 16 | out = append(out, v) 17 | failed = true 18 | } 19 | } 20 | return 21 | } 22 | -------------------------------------------------------------------------------- /functions/elem.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | // Elem returns true if the slice contains the element 4 | // Can be generated for any type. 5 | func (s SliceType) Elem(el ElementType) bool { 6 | for _, e := range s { 7 | if e == el { 8 | return true 9 | } 10 | } 11 | return false 12 | } 13 | -------------------------------------------------------------------------------- /functions/filter.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | // Filter returns a slice containing only the elements that match the predicate. 4 | // Can be generated for any type. 5 | func (s SliceType) Filter(f func(ElementType) bool) (out SliceType) { 6 | for _, v := range s { 7 | if f(v) { 8 | out = append(out, v) 9 | } 10 | } 11 | return 12 | } 13 | -------------------------------------------------------------------------------- /functions/foldl.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | // Foldl reduces a list by iteratively applying f from left->right. Thus, for an empty slice, the result is the default zero-value. 4 | func (s SliceType) Foldl(z ElementType, f func(e1, e2 ElementType) ElementType) (out ElementType) { 5 | if len(s) == 0 { 6 | return 7 | } 8 | out = f(z, s[0]) 9 | for _, v := range s[1:] { 10 | out = f(out, v) 11 | } 12 | return 13 | } 14 | -------------------------------------------------------------------------------- /functions/foldl1.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | // Foldl1 reduces a list by iteratively applying f from left->right. Thus, for an empty slice, the result is the default zero-value. 4 | func (s SliceType) Foldl1(f func(e1, e2 ElementType) ElementType) (out ElementType) { 5 | if len(s) == 0 { 6 | return 7 | } 8 | out = s[0] 9 | for _, v := range s[1:] { 10 | out = f(out, v) 11 | } 12 | return 13 | } 14 | -------------------------------------------------------------------------------- /functions/foldr.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | // Foldr reduces a list by iteratively applying f from right -> left. Thus, for an empty slice, the result is the default zero-value. 4 | func (s SliceType) Foldr(e ElementType, f func(e1, e2 ElementType) ElementType) (out ElementType) { 5 | if len(s) == 0 { 6 | return 7 | } 8 | 9 | end := len(s) - 1 10 | out = f(s[end], e) 11 | 12 | for i := end - 1; i >= 0; i-- { 13 | out = f(s[i], out) 14 | } 15 | 16 | return 17 | } 18 | -------------------------------------------------------------------------------- /functions/foldr1.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | // Foldr1 reduces a list by iteratively applying f from right -> left. Thus, for an empty slice, the result is the default zero-value. 4 | func (s SliceType) Foldr1(f func(e1, e2 ElementType) ElementType) (out ElementType) { 5 | if len(s) == 0 { 6 | return 7 | } 8 | 9 | end := len(s) - 1 10 | out = s[end] 11 | 12 | for i := end - 1; i >= 0; i-- { 13 | out = f(s[i], out) 14 | } 15 | 16 | return 17 | } 18 | -------------------------------------------------------------------------------- /functions/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/DylanMeeus/hasgo/functions 2 | 3 | go 1.13 4 | -------------------------------------------------------------------------------- /functions/group.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | // Group returns a list of lists where each list contains only equal elements and the concatenation of the 4 | // result is equal to the argument. 5 | // Can be generated for any type. 6 | func (s SliceType) Group() (out SliceSliceType) { 7 | current := SliceType{} 8 | 9 | for i, v := range s { 10 | current = append(current, v) 11 | if i == len(s)-1 || v != s[i+1] { 12 | out = append(out, current) 13 | current = SliceType{} 14 | } 15 | } 16 | 17 | return 18 | } 19 | -------------------------------------------------------------------------------- /functions/head.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | // Head returns the first element in the slice. 4 | // If no element is found, returns the zero-value of the type. 5 | // Can be generated for any type. 6 | func (s SliceType) Head() (out ElementType) { 7 | if len(s) > 0 { 8 | out = s[0] 9 | } 10 | return 11 | } 12 | -------------------------------------------------------------------------------- /functions/init.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | // Init takes n-1 elements from a slice, where n = len(list). 4 | // Can be generated for any type. 5 | func (s SliceType) Init() (out SliceType) { 6 | if len(s) == 0 { 7 | return 8 | } 9 | slicecopy := append([]ElementType(nil), s...) 10 | return slicecopy[:len(s)-1] 11 | } 12 | -------------------------------------------------------------------------------- /functions/inits.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | // Inits returns all inits of a sequence, in order of small to large, as if it were called recursively. 4 | // Can be generated for any type. 5 | func (s SliceType) Inits() (out SliceSliceType) { 6 | out = append(out, make(SliceType, 0)) 7 | for i := range s { 8 | init := make(SliceType, i+1) 9 | for n := 0; n <= i; n++ { 10 | init[n] = s[n] 11 | } 12 | out = append(out, init) 13 | } 14 | return 15 | } 16 | -------------------------------------------------------------------------------- /functions/intercalate.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | // Intercalate inserts the method receiver slice into the function slice at each step. 4 | // Can be generated for any type. 5 | func (s SliceType) Intercalate(ss SliceSliceType) (out SliceType) { 6 | for i, slice := range ss { 7 | for _, el := range slice { 8 | out = append(out, el) 9 | } 10 | if i == len(ss)-1 { 11 | break 12 | } 13 | for _, el := range s { 14 | out = append(out, el) 15 | } 16 | } 17 | return out 18 | } 19 | -------------------------------------------------------------------------------- /functions/intersperse.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | // Intersperse inserts the receiving value between each element of the method receiver. 4 | // Can be generated for any type. 5 | func (s SliceType) Intersperse(value ElementType) (out SliceType) { 6 | for i, el := range s { 7 | out = append(out, el) 8 | if i == len(s)-1 { 9 | break 10 | } 11 | out = append(out, value) 12 | } 13 | return 14 | } 15 | -------------------------------------------------------------------------------- /functions/isprefixof.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | // IsPrefixOf returns true if the current sliceType is a prefix of the passed one. 4 | // Can be generated for any time. 5 | func (s SliceType) IsPrefixOf(in SliceType) bool { 6 | if len(s) > len(in) { 7 | return false 8 | } 9 | for i, v := range s { 10 | if in[i] != v { 11 | return false 12 | } 13 | } 14 | return true 15 | } 16 | -------------------------------------------------------------------------------- /functions/last.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | // Last returns the last element in the slice 4 | // If no element is found, returns the zero-value of the type 5 | // Can be generated for any type. 6 | func (s SliceType) Last() (out ElementType) { 7 | if len(s) > 0 { 8 | out = s[len(s)-1] 9 | } 10 | return 11 | } 12 | -------------------------------------------------------------------------------- /functions/length.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | // Length returns the length (len) of a slice. 4 | // Can be generated for any type. 5 | func (s SliceType) Length() int { 6 | return len(s) 7 | } 8 | -------------------------------------------------------------------------------- /functions/main.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | // Symbol is represents a data token to be parsed. 4 | type Symbol interface { 5 | Symbol() 6 | } 7 | 8 | // Types for which the function can be generated 9 | const ( 10 | ForNumbers = "ForNumbers" 11 | ForStrings = "ForStrings" 12 | ForStructs = "ForStructs" 13 | ) 14 | 15 | // ElementType represents a single entry in a slice. 16 | type ElementType float64 17 | 18 | // SliceType represents a 1D slice. 19 | type SliceType []ElementType 20 | 21 | // SliceSliceType represents a 2D slice. 22 | type SliceSliceType [][]ElementType 23 | 24 | // Template is the content of a function file. 25 | type Template string 26 | 27 | var ( 28 | templates = map[string][]string{ 29 | "abs.go": {ForNumbers}, 30 | "all.go": {ForNumbers, ForStrings, ForStructs}, 31 | "any.go": {ForNumbers, ForStrings, ForStructs}, 32 | "average.go": {ForNumbers}, 33 | "break.go": {ForNumbers, ForStrings, ForStructs}, 34 | "delete.go": {ForNumbers, ForStrings, ForStructs}, 35 | "drop.go": {ForNumbers, ForStrings, ForStructs}, 36 | "dropwhile.go": {ForNumbers, ForStrings, ForStructs}, 37 | "elem.go": {ForNumbers, ForStrings, ForStructs}, 38 | "filter.go": {ForNumbers, ForStrings, ForStructs}, 39 | "foldl.go": {ForNumbers, ForStrings, ForStructs}, 40 | "foldl1.go": {ForNumbers, ForStrings, ForStructs}, 41 | "foldr.go": {ForNumbers, ForStrings, ForStructs}, 42 | "foldr1.go": {ForNumbers, ForStrings, ForStructs}, 43 | "group.go": {ForNumbers, ForStrings, ForStructs}, 44 | "head.go": {ForNumbers, ForStrings, ForStructs}, 45 | "init.go": {ForNumbers, ForStrings, ForStructs}, 46 | "inits.go": {ForNumbers, ForStrings, ForStructs}, 47 | "intercalate.go": {ForNumbers, ForStrings, ForStructs}, 48 | "intersperse.go": {ForNumbers, ForStrings, ForStructs}, 49 | "isprefixof.go": {ForNumbers, ForStrings, ForStructs}, 50 | "last.go": {ForNumbers, ForStrings, ForStructs}, 51 | "length.go": {ForNumbers, ForStrings, ForStructs}, 52 | "map.go": {ForNumbers, ForStrings, ForStructs}, 53 | "maximum.go": {ForNumbers}, 54 | "maximumby.go": {ForNumbers, ForStrings, ForStructs}, 55 | "minimum.go": {ForNumbers}, 56 | "modes.go": {ForNumbers, ForStrings, ForStructs}, 57 | "nub.go": {ForNumbers, ForStrings, ForStructs}, 58 | "null.go": {ForNumbers, ForStrings, ForStructs}, 59 | "product.go": {ForNumbers}, 60 | "reverse.go": {ForNumbers, ForStrings, ForStructs}, 61 | "scanl.go": {ForNumbers, ForStrings, ForStructs}, 62 | "sort.go": {ForNumbers, ForStrings}, 63 | "span.go": {ForNumbers, ForStrings, ForStructs}, 64 | "splitat.go": {ForNumbers, ForStrings, ForStructs}, 65 | "sum.go": {ForNumbers, ForStrings}, 66 | "tail.go": {ForNumbers, ForStrings, ForStructs}, 67 | "tails.go": {ForNumbers, ForStrings, ForStructs}, 68 | "take.go": {ForNumbers, ForStrings, ForStructs}, 69 | "takewhile.go": {ForNumbers, ForStrings, ForStructs}, 70 | "uncons.go": {ForNumbers, ForStrings, ForStructs}, 71 | "unlines.go": {ForNumbers, ForStrings, ForStructs}, 72 | "unwords.go": {ForNumbers, ForStrings, ForStructs}, 73 | } 74 | ) 75 | 76 | // Templates returns all entries in the template map 77 | func Templates() map[string][]string { 78 | return templates 79 | } 80 | -------------------------------------------------------------------------------- /functions/map.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | // Map return a new slice with the map operation applied to each element. 4 | // Can be generated for any type. 5 | func (s SliceType) Map(f func(ElementType) ElementType) (out SliceType) { 6 | if f == nil { 7 | return s 8 | } 9 | for _, v := range s { 10 | out = append(out, f(v)) 11 | } 12 | return 13 | } 14 | -------------------------------------------------------------------------------- /functions/maximum.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | // Maximum returns the maximum in a slice. 4 | // Can be generated for number types. 5 | func (s SliceType) Maximum() (out ElementType) { 6 | if len(s) == 0 { 7 | return 8 | } 9 | for _, i := range s { 10 | if i > out { 11 | out = i 12 | } 13 | } 14 | return 15 | } 16 | -------------------------------------------------------------------------------- /functions/maximumby.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | // MaximumBy returns the maximum elements according to a custom comparator. 4 | // Can be generated for any type. 5 | func (s SliceType) MaximumBy(f func(e1, e2 ElementType) ElementType) (max ElementType) { 6 | if len(s) == 0 { 7 | return 8 | } 9 | max = s[0] 10 | for _, el := range s[1:] { 11 | max = f(max, el) 12 | } 13 | return 14 | } 15 | -------------------------------------------------------------------------------- /functions/minimum.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | // Minimum returns the minimum of a slice. 4 | // Can be generated for number types. 5 | func (s SliceType) Minimum() ElementType { 6 | if len(s) == 0 { 7 | return 0 // bit strange? 8 | } 9 | min := s[0] 10 | for _, i := range s { 11 | if i < min { 12 | min = i 13 | } 14 | } 15 | return min 16 | } 17 | -------------------------------------------------------------------------------- /functions/modes.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | // Modes returns the elements with highest frequency in the slice. 4 | // Can be generated for any type. 5 | func (s SliceType) Modes() (out SliceType) { 6 | if len(s) == 0 { 7 | return 8 | } 9 | 10 | counts := make(map[ElementType]int) 11 | for _, v := range s { 12 | counts[v]++ 13 | } 14 | 15 | var max int 16 | for _, v := range counts { 17 | if v > max { 18 | max = v 19 | } 20 | } 21 | 22 | for k, v := range counts { 23 | if v == max { 24 | out = append(out, k) 25 | } 26 | } 27 | 28 | return 29 | } 30 | -------------------------------------------------------------------------------- /functions/nub.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | // Nub returns a slice containing only the unique elements of the receiver. 4 | // The order of the elements is preserved. 5 | // Can be generated for any type. 6 | func (s SliceType) Nub() (out SliceType) { 7 | if len(s) == 0 { 8 | return 9 | } 10 | 11 | contains := make(map[ElementType]struct{}) 12 | for _, v := range s { 13 | if _, ok := contains[v]; !ok { 14 | contains[v] = struct{}{} 15 | out = append(out, v) 16 | } 17 | } 18 | return 19 | } 20 | -------------------------------------------------------------------------------- /functions/null.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | // Null returns true the slice is empty. 4 | // Can be generated for any type. 5 | func (s SliceType) Null() bool { 6 | return len(s) == 0 7 | } 8 | -------------------------------------------------------------------------------- /functions/product.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | // Product returns the product of all elements in the slice. 4 | // Can be generated for any number type. 5 | func (s SliceType) Product() ElementType { 6 | var prod ElementType 7 | for _, v := range s { 8 | prod += v 9 | } 10 | return prod 11 | } 12 | -------------------------------------------------------------------------------- /functions/reverse.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | // Reverse returns the reversed slice. 4 | // Can be generated for any type. 5 | func (s SliceType) Reverse() (out SliceType) { 6 | for i := len(s) - 1; i >= 0; i-- { 7 | out = append(out, s[i]) 8 | } 9 | return 10 | } 11 | -------------------------------------------------------------------------------- /functions/scanl.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | // Scanl reduces a list by iteratively applying f from left->right and then returns each iteration in a slice. 4 | func (s SliceType) Scanl(e ElementType, f func(e1, e2 ElementType) ElementType) (out SliceType) { 5 | if len(s) == 0 { 6 | return 7 | } 8 | 9 | out = append(out, e) 10 | last := e 11 | 12 | for _, v := range s { 13 | last = f(last, v) 14 | out = append(out, last) 15 | } 16 | 17 | return 18 | } 19 | -------------------------------------------------------------------------------- /functions/sort.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | import ( 4 | "sort" 5 | ) 6 | 7 | // Sort is a wrapper around go sort function. 8 | // Can be generated for any type. 9 | func (s SliceType) Sort() SliceType { 10 | out := make(SliceType, len(s)) 11 | copy(out, s) 12 | sort.Slice(out, func(i, j int) bool { 13 | return out[i] < out[j] 14 | }) 15 | return out 16 | } 17 | -------------------------------------------------------------------------------- /functions/span.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | // Span returns a tuple of any elements that satisfy the predicate up until the first failure, followed by 4 | // the rest of the elements. 5 | // Can be generated for any type. 6 | func (s SliceType) Span(f func(ElementType) bool) (before SliceType, after SliceType) { 7 | if f == nil { 8 | return before, s 9 | } 10 | 11 | failed := false 12 | 13 | for _, v := range s { 14 | if failed || !f(v) { 15 | after = append(after, v) 16 | failed = true 17 | } else { 18 | before = append(before, v) 19 | } 20 | } 21 | 22 | return 23 | } 24 | -------------------------------------------------------------------------------- /functions/splitat.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | // SplitAt splits the slice at the given index, returning before and after as a tuple. 4 | // Can be generated for any type. 5 | func (s SliceType) SplitAt(i int) (before, after SliceType) { 6 | for k, v := range s { 7 | if k < i { 8 | before = append(before, v) 9 | } else { 10 | after = append(after, v) 11 | } 12 | } 13 | return 14 | } 15 | -------------------------------------------------------------------------------- /functions/sum.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | // Sum returns the sum of all elements in the slice. 4 | // Can be generated for any number type. 5 | func (s SliceType) Sum() ElementType { 6 | var sum ElementType 7 | for _, v := range s { 8 | sum += v 9 | } 10 | return sum 11 | } 12 | -------------------------------------------------------------------------------- /functions/tail.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | // Tail takes [1 -> n] elements from a slice, where n = len(list) 4 | // Returns an empty slice if there are less than 2 elements in slice 5 | // Can be generated for any type. 6 | func (s SliceType) Tail() (out SliceType) { 7 | if len(s) <= 1 { 8 | return 9 | } 10 | slicecopy := append([]ElementType(nil), s...) 11 | return slicecopy[1:] 12 | } 13 | -------------------------------------------------------------------------------- /functions/tails.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | // Tails returns all tails of a sequence, in order of large to small, as if it were called recursively. 4 | // Can be generated for any type. 5 | func (s SliceType) Tails() (out SliceSliceType) { 6 | slicecopy := append([]ElementType(nil), s...) 7 | for range s { 8 | out = append(out, slicecopy) 9 | slicecopy = slicecopy[1:] 10 | } 11 | out = append(out, make(SliceType, 0)) 12 | return 13 | } 14 | -------------------------------------------------------------------------------- /functions/take.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | // Take takes the first n elements of the slice, or the entire slice if n > len(slice). 4 | // Can be generated for any type. 5 | func (s SliceType) Take(n uint64) (out SliceType) { 6 | if len(s) == 0 { 7 | return 8 | } 9 | out = make(SliceType, len(s)) 10 | copy(out, s) 11 | if n < uint64(len(s)) { 12 | return out[:n] 13 | } 14 | return 15 | } 16 | -------------------------------------------------------------------------------- /functions/takewhile.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | // TakeWhile continues appending to the output as long as the predicate is satisfied. 4 | // Can be generated for any type. 5 | func (s SliceType) TakeWhile(p func(ElementType) bool) (out SliceType) { 6 | if len(s) == 0 { 7 | return 8 | } 9 | for _, e := range s { 10 | if !p(e) { 11 | return 12 | } 13 | out = append(out, e) 14 | } 15 | return 16 | } 17 | -------------------------------------------------------------------------------- /functions/uncons.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | // Uncons decomposes a slice into the head and tail component. 4 | // Can be generated for any type. 5 | func (s SliceType) Uncons() (head ElementType, tail SliceType) { 6 | return s.Head(), s.Tail() 7 | } 8 | -------------------------------------------------------------------------------- /functions/unlines.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // Unlines joins together the string representation of the slice with newlines after each element. 8 | // Can be generated for any type. 9 | func (s SliceType) Unlines() (out string) { 10 | for i, v := range s { 11 | out += fmt.Sprintf("%v", v) 12 | if i != len(s)-1 { 13 | out += "\n" 14 | } 15 | } 16 | return 17 | } 18 | -------------------------------------------------------------------------------- /functions/unwords.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // Unwords joins together the string representation of the slice with newlines after each element. 8 | // Can be generated for any type. 9 | func (s SliceType) Unwords() (out string) { 10 | for i, v := range s { 11 | out += fmt.Sprintf("%v", v) 12 | if i != len(s)-1 { 13 | out += " " 14 | } 15 | } 16 | return 17 | } 18 | -------------------------------------------------------------------------------- /generator.go: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | 3 | package main 4 | 5 | import ( 6 | fun "github.com/DylanMeeus/hasgo/functions" 7 | "io/ioutil" 8 | "os" 9 | "strings" 10 | "text/template" 11 | ) 12 | 13 | var packageTemplate = template.Must(template.New(""). 14 | Parse("// Code generated by go generate; DO NOT EDIT.\n" + 15 | "package main\n" + 16 | "\n" + 17 | "var hasgoTemplates = map[string]string{\n" + 18 | "{{ range $fn, $file := . }}" + 19 | "\t\"{{ $fn }}\": `{{ $file }}`,\n" + 20 | "{{ end }}" + 21 | "}\n")) 22 | 23 | var domainTemplate = template.Must(template.New(""). 24 | Parse("\n" + 25 | "const (\n ForNumbers = \"ForNumbers\"\nForStrings = \"ForStrings\"\n" + 26 | "ForStructs = \"ForStructs\"\n)\n" + 27 | "var funcDomains = map[string][]string{\n" + 28 | "{{ range $fn, $arr := . }}" + 29 | "\t\"{{ $fn }}\": []string{ {{ range $index, $dom := $arr }}" + 30 | " {{if $index}} ,{{end}} {{$dom}} {{end}} },\n" + 31 | "{{ end }}" + 32 | "}\n")) 33 | 34 | // generate the templates that will be used for hasgo 35 | func main() { 36 | data := map[string]string{} 37 | for k := range fun.Templates() { 38 | content, err := ioutil.ReadFile("./functions/" + k) 39 | // remove the package statement.. 40 | parts := strings.Split(string(content), "\n") 41 | sanitized := strings.Join(parts[1:], "\n") 42 | if err != nil { 43 | panic(err) 44 | } 45 | data[k] = sanitized 46 | } 47 | f, err := os.Create("template.go") 48 | if err != nil { 49 | panic(err) 50 | } 51 | defer f.Close() 52 | packageTemplate.Execute(f, data) 53 | domainTemplate.Execute(f, fun.Templates()) 54 | } 55 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/DylanMeeus/hasgo 2 | 3 | go 1.13 4 | 5 | require ( 6 | github.com/DylanMeeus/hasgo/types v0.0.0-20191001225624-a7a7cd8574d1 7 | golang.org/x/tools v0.0.0-20191010171213-8abd42400456 8 | ) 9 | 10 | replace github.com/DylanMeeus/hasgo/functions v0.0.0 => ./functions 11 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/DylanMeeus/hasgo/types v0.0.0-20191001225624-a7a7cd8574d1 h1:kVjY+MO85qHG5BWLlHI22YlFS3SZgRhoFinT8McoVhs= 2 | github.com/DylanMeeus/hasgo/types v0.0.0-20191001225624-a7a7cd8574d1/go.mod h1:P0jbBiMGpKS6NnhmaQAbua54O5bnRVLOFQPP+1wx6NE= 3 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 4 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 5 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 6 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 7 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 8 | golang.org/x/tools v0.0.0-20191010171213-8abd42400456 h1:LR16zMCx87X52rsLOtnByklL2K/xWUKAo1Nm7AA4HA0= 9 | golang.org/x/tools v0.0.0-20191010171213-8abd42400456/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 10 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 11 | -------------------------------------------------------------------------------- /hasgo.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "flag" 6 | "fmt" 7 | "go/format" 8 | "golang.org/x/tools/go/packages" 9 | "io/ioutil" 10 | "os" 11 | "sort" 12 | "strings" 13 | ) 14 | 15 | const ( 16 | elementTypeSymbol = "ElementType" 17 | sliceTypeSymbol = "SliceType" 18 | sliceSliceTypeSymbol = "SliceSliceType" // todo: generalize for N slices 19 | ) 20 | 21 | var ( 22 | unitType = flag.String("T", "", "Type for which to generate data") 23 | sliceType = flag.String("S", "", "Corresponding Slice Type for T") 24 | packag = flag.String("P", "types", "Package for which to generate") 25 | ofilename = flag.String("N", "", "name for the generated file (_hasgo.go will be appended)") 26 | numberTypes = map[string]struct{}{ 27 | "int": {}, 28 | "int32": {}, 29 | "int64": {}, 30 | "uint": {}, 31 | "uint32": {}, 32 | "uint64": {}, 33 | "float": {}, 34 | "float32": {}, 35 | "float64": {}, 36 | } 37 | stringTypes = map[string]struct{}{ 38 | "string": {}, 39 | } 40 | ) 41 | 42 | func check(e error) { 43 | if e != nil { 44 | panic(e) 45 | } 46 | } 47 | 48 | // the Type / sliceType for which we are generating data.. 49 | type symbols struct { 50 | T, ST string 51 | } 52 | 53 | type generator struct { 54 | buf bytes.Buffer // accumulate the output 55 | pkg string // package in which to place the generated code. 56 | imports map[string]struct{} // the imports that the generator needs to add 57 | } 58 | 59 | // currently hasgo works like this: 60 | // once the generator is trigger, I scan all files in the named packages 61 | // I generate one hasgo file with functions 62 | // all the functions get stored here 63 | // I write out _once_, collecting all data 64 | // Importantly, hasgo should trigger only once.. I should figure out how to do so 65 | 66 | func main() { 67 | flag.Parse() 68 | fmt.Printf("type: %v - slice: %v\n", *unitType, *sliceType) 69 | sym := symbols{*unitType, *sliceType} 70 | g := generator{ 71 | imports: map[string]struct{}{}, 72 | pkg: *packag, 73 | } 74 | g.parsePackage(os.Args, nil) 75 | // stringer prints everything in one file. This might be bad. 76 | // but let's roll with it for now :-) 77 | g.generate(sym) 78 | filename := fmt.Sprintf("%v_hasgo.go", *sliceType) 79 | if ofilename != nil && *ofilename != "" { 80 | filename = fmt.Sprintf("%v_hasgo.go", *ofilename) 81 | } 82 | err := ioutil.WriteFile(filename, g.format(), 0644) 83 | if err != nil { 84 | panic(err) 85 | } 86 | } 87 | 88 | // is the function valid for the type? 89 | func validFunction(function, T string) bool { 90 | domains, ok := funcDomains[function] 91 | if !ok { 92 | return false 93 | } 94 | for _, d := range domains { 95 | switch d { 96 | case ForNumbers: 97 | if _, ok := numberTypes[T]; ok { 98 | return true 99 | } 100 | break 101 | case ForStrings: 102 | if _, ok := stringTypes[T]; ok { 103 | return true 104 | } 105 | break 106 | case ForStructs: 107 | // everything that is not a string or number we will consider a struct! 108 | if _, ok := numberTypes[T]; !ok { 109 | if _, ok := stringTypes[T]; !ok { 110 | return true 111 | } 112 | } 113 | break 114 | 115 | } 116 | } 117 | return false 118 | } 119 | 120 | // write the data for the generator 121 | func (g *generator) generate(s symbols) { 122 | funcs := []string{} 123 | for function := range hasgoTemplates { 124 | funcs = append(funcs, function) 125 | } 126 | sort.Strings(funcs) 127 | for _, function := range funcs { 128 | template := hasgoTemplates[function] 129 | if !validFunction(function, s.T) { 130 | continue 131 | } 132 | template, imports := extractImports(template) 133 | g.addImports(imports) 134 | g.printf("// =============== %v =================\n", function) 135 | g.print(generify(template, s)) 136 | g.newline() 137 | } 138 | } 139 | 140 | // extracts the imports and removes them from the template 141 | // we assume that the go code is correctly formatted! 142 | func extractImports(template string) (outtemp string, imports []string) { 143 | // split template into lines 144 | // check for import statements in line 145 | lines := strings.Split(template, "\n") 146 | nonImportLines := []string{} 147 | for i := 0; i < len(lines); { 148 | line := lines[i] 149 | if strings.Contains(line, "import") { 150 | // determine if it's a single import or multiple.. 151 | if strings.Contains(line, "(") { 152 | // implement 153 | i++ 154 | line := lines[i] 155 | // check end condition 156 | for !strings.Contains(line, ")") { 157 | imports = append(imports, line) 158 | i++ 159 | line = lines[i] 160 | } 161 | i++ 162 | continue 163 | } else { 164 | line = strings.TrimSpace(line)[len("import"):] 165 | imports = append(imports, line) 166 | i++ 167 | continue 168 | } 169 | } 170 | nonImportLines = append(nonImportLines, line) 171 | i++ 172 | } 173 | 174 | return strings.Join(nonImportLines, "\n"), imports 175 | } 176 | 177 | // replace the placeholders by the correct symbols 178 | func generify(template string, sym symbols) (out string) { 179 | out = template 180 | out = strings.Replace(out, elementTypeSymbol, sym.T, -1) 181 | out = strings.Replace(out, sliceSliceTypeSymbol, "[][]"+sym.T, -1) 182 | out = strings.Replace(out, sliceTypeSymbol, sym.ST, -1) 183 | return 184 | } 185 | 186 | func (g *generator) printf(format string, args ...interface{}) { 187 | fmt.Fprintf(&g.buf, format, args...) 188 | } 189 | 190 | func (g *generator) print(s string) { 191 | fmt.Fprint(&g.buf, s) 192 | } 193 | 194 | func (g *generator) newline() { 195 | g.printf("\n") 196 | } 197 | 198 | func (g *generator) addImports(imports []string) { 199 | for _, imp := range imports { 200 | // sanitize: 201 | sane := strings.TrimSpace(imp) 202 | g.imports[sane] = struct{}{} 203 | } 204 | } 205 | 206 | // analyze the package 207 | func (g *generator) parsePackage(patterns []string, tags []string) { 208 | cfg := &packages.Config{ 209 | Mode: packages.LoadSyntax, 210 | Tests: false, 211 | BuildFlags: []string{fmt.Sprintf("-tags=%s", strings.Join(tags, " "))}, 212 | } 213 | pkgs, err := packages.Load(cfg, patterns...) 214 | check(err) 215 | if len(pkgs) == 0 { 216 | panic("not enough packages") 217 | } 218 | fmt.Printf("packages %v\n", pkgs) 219 | g.addPackage(pkgs[0]) 220 | } 221 | 222 | // add a package to the generator 223 | func (g *generator) addPackage(pkg *packages.Package) { 224 | fmt.Println("adding files..") 225 | for _, file := range pkg.Syntax { 226 | fmt.Printf("file %v\n", file) 227 | } 228 | } 229 | 230 | // return all unique imports 231 | func (g *generator) listImports() (out []string) { 232 | for k := range g.imports { 233 | out = append(out, k) 234 | } 235 | return 236 | } 237 | 238 | // print the formatted source code 239 | // adds the package declaration + imports 240 | func (g *generator) format() []byte { 241 | code := "// Package " + g.pkg + " contains code generated by hasgo. [DO NOT EDIT!]" + 242 | "\n" + 243 | "package " + g.pkg + "\n" 244 | 245 | if imports := g.listImports(); len(imports) > 0 { 246 | code += "import (\n" 247 | code += strings.Join(imports, "\n") + "\n)\n" 248 | } 249 | // add our generated functions 250 | src := append([]byte(code), g.buf.Bytes()...) 251 | src, err := format.Source(src) 252 | if err != nil { 253 | // should never happen. But, during development, might. 254 | fmt.Println("Printing code without formatting") 255 | return append([]byte(code), g.buf.Bytes()...) 256 | } 257 | return src 258 | } 259 | -------------------------------------------------------------------------------- /template.go: -------------------------------------------------------------------------------- 1 | // Code generated by go generate; DO NOT EDIT. 2 | package main 3 | 4 | var hasgoTemplates = map[string]string{ 5 | "abs.go": ` 6 | import ( 7 | "math" 8 | ) 9 | 10 | // Abs returns the absolute value of all elements in the slice. 11 | // Can be generated for number-types. 12 | func (s SliceType) Abs() (out SliceType) { 13 | for _, v := range s { 14 | out = append(out, ElementType(math.Abs(float64(v)))) 15 | } 16 | return 17 | } 18 | `, 19 | "all.go": ` 20 | // All returns true if all elements of the slice satisfy the predicate. 21 | // Can be generated for any type. 22 | func (s SliceType) All(f func(ElementType) bool) bool { 23 | if f == nil { 24 | return false 25 | } 26 | for _, v := range s { 27 | if !f(v) { 28 | return false 29 | } 30 | } 31 | return true 32 | } 33 | `, 34 | "any.go": ` 35 | // Any returns true if any of the elements satisfy the predicate. 36 | // Can be generated for any type. 37 | func (s SliceType) Any(f func(ElementType) bool) bool { 38 | if f == nil { 39 | return false 40 | } 41 | for _, v := range s { 42 | if f(v) { 43 | return true 44 | } 45 | } 46 | return false 47 | } 48 | `, 49 | "average.go": ` 50 | // Average returns the average of all elements in the slice. 51 | // Can be generated for all number types. 52 | func (s SliceType) Average() float64 { 53 | var sum ElementType 54 | if len(s) == 0 { 55 | return float64(0) 56 | } 57 | for _, i := range s { 58 | sum += i 59 | } 60 | return float64(sum) / float64(len(s)) 61 | } 62 | `, 63 | "break.go": ` 64 | // Break returns a tuple of any elements that do not satisfy the predicate up until the first time it passes, followed 65 | // by the rest of the elements. 66 | // Can be generated on any type. 67 | func (s SliceType) Break(f func(ElementType) bool) (before SliceType, after SliceType) { 68 | if f == nil { 69 | return before, s 70 | } 71 | 72 | passed := false 73 | 74 | for _, v := range s { 75 | if passed || f(v) { 76 | after = append(after, v) 77 | passed = true 78 | } else { 79 | before = append(before, v) 80 | } 81 | } 82 | 83 | return 84 | } 85 | `, 86 | "delete.go": ` 87 | // Delete returns a slice with the first matching element 88 | // removed from the slice. 89 | // Can be generated for any type. 90 | func (s SliceType) Delete(e ElementType) (out SliceType) { 91 | deleted := false 92 | for _, v := range s { 93 | if deleted || v != e { 94 | out = append(out, v) 95 | } else { 96 | deleted = true 97 | } 98 | } 99 | return 100 | } 101 | `, 102 | "drop.go": ` 103 | // Drop returns a new Slice with the elements after the provided key. 104 | // Can be generated for any type. 105 | func (s SliceType) Drop(i int) (out SliceType) { 106 | for i < len(s) { 107 | out = append(out, s[i]) 108 | i++ 109 | } 110 | return 111 | } 112 | `, 113 | "dropwhile.go": ` 114 | // DropWhile returns a new slice containing all elements after the predicate fails for the first time. 115 | // Can be generated for any type. 116 | func (s SliceType) DropWhile(f func(ElementType) bool) (out SliceType) { 117 | if f == nil { 118 | return s 119 | } 120 | failed := false 121 | for _, v := range s { 122 | if failed { 123 | out = append(out, v) 124 | continue 125 | } 126 | if !f(v) { 127 | out = append(out, v) 128 | failed = true 129 | } 130 | } 131 | return 132 | } 133 | `, 134 | "elem.go": ` 135 | // Elem returns true if the slice contains the element 136 | // Can be generated for any type. 137 | func (s SliceType) Elem(el ElementType) bool { 138 | for _, e := range s { 139 | if e == el { 140 | return true 141 | } 142 | } 143 | return false 144 | } 145 | `, 146 | "filter.go": ` 147 | // Filter returns a slice containing only the elements that match the predicate. 148 | // Can be generated for any type. 149 | func (s SliceType) Filter(f func(ElementType) bool) (out SliceType) { 150 | for _, v := range s { 151 | if f(v) { 152 | out = append(out, v) 153 | } 154 | } 155 | return 156 | } 157 | `, 158 | "foldl.go": ` 159 | // Foldl reduces a list by iteratively applying f from left->right. Thus, for an empty slice, the result is the default zero-value. 160 | func (s SliceType) Foldl(z ElementType, f func(e1, e2 ElementType) ElementType) (out ElementType) { 161 | if len(s) == 0 { 162 | return 163 | } 164 | out = f(z, s[0]) 165 | for _, v := range s[1:] { 166 | out = f(out, v) 167 | } 168 | return 169 | } 170 | `, 171 | "foldl1.go": ` 172 | // Foldl1 reduces a list by iteratively applying f from left->right. Thus, for an empty slice, the result is the default zero-value. 173 | func (s SliceType) Foldl1(f func(e1, e2 ElementType) ElementType) (out ElementType) { 174 | if len(s) == 0 { 175 | return 176 | } 177 | out = s[0] 178 | for _, v := range s[1:] { 179 | out = f(out, v) 180 | } 181 | return 182 | } 183 | `, 184 | "foldr.go": ` 185 | // Foldr reduces a list by iteratively applying f from right -> left. Thus, for an empty slice, the result is the default zero-value. 186 | func (s SliceType) Foldr(e ElementType, f func(e1, e2 ElementType) ElementType) (out ElementType) { 187 | if len(s) == 0 { 188 | return 189 | } 190 | 191 | end := len(s) - 1 192 | out = f(s[end], e) 193 | 194 | for i := end - 1; i >= 0; i-- { 195 | out = f(s[i], out) 196 | } 197 | 198 | return 199 | } 200 | `, 201 | "foldr1.go": ` 202 | // Foldr1 reduces a list by iteratively applying f from right -> left. Thus, for an empty slice, the result is the default zero-value. 203 | func (s SliceType) Foldr1(f func(e1, e2 ElementType) ElementType) (out ElementType) { 204 | if len(s) == 0 { 205 | return 206 | } 207 | 208 | end := len(s) - 1 209 | out = s[end] 210 | 211 | for i := end - 1; i >= 0; i-- { 212 | out = f(s[i], out) 213 | } 214 | 215 | return 216 | } 217 | `, 218 | "group.go": ` 219 | // Group returns a list of lists where each list contains only equal elements and the concatenation of the 220 | // result is equal to the argument. 221 | // Can be generated for any type. 222 | func (s SliceType) Group() (out SliceSliceType) { 223 | current := SliceType{} 224 | 225 | for i, v := range s { 226 | current = append(current, v) 227 | if i == len(s)-1 || v != s[i+1] { 228 | out = append(out, current) 229 | current = SliceType{} 230 | } 231 | } 232 | 233 | return 234 | } 235 | `, 236 | "head.go": ` 237 | // Head returns the first element in the slice. 238 | // If no element is found, returns the zero-value of the type. 239 | // Can be generated for any type. 240 | func (s SliceType) Head() (out ElementType) { 241 | if len(s) > 0 { 242 | out = s[0] 243 | } 244 | return 245 | } 246 | `, 247 | "init.go": ` 248 | // Init takes n-1 elements from a slice, where n = len(list). 249 | // Can be generated for any type. 250 | func (s SliceType) Init() (out SliceType) { 251 | if len(s) == 0 { 252 | return 253 | } 254 | slicecopy := append([]ElementType(nil), s...) 255 | return slicecopy[:len(s)-1] 256 | } 257 | `, 258 | "inits.go": ` 259 | // Inits returns all inits of a sequence, in order of small to large, as if it were called recursively. 260 | // Can be generated for any type. 261 | func (s SliceType) Inits() (out SliceSliceType) { 262 | out = append(out, make(SliceType, 0)) 263 | for i := range s { 264 | init := make(SliceType, i+1) 265 | for n := 0; n <= i; n++ { 266 | init[n] = s[n] 267 | } 268 | out = append(out, init) 269 | } 270 | return 271 | } 272 | `, 273 | "intercalate.go": ` 274 | // Intercalate inserts the method receiver slice into the function slice at each step. 275 | // Can be generated for any type. 276 | func (s SliceType) Intercalate(ss SliceSliceType) (out SliceType) { 277 | for i, slice := range ss { 278 | for _, el := range slice { 279 | out = append(out, el) 280 | } 281 | if i == len(ss)-1 { 282 | break 283 | } 284 | for _, el := range s { 285 | out = append(out, el) 286 | } 287 | } 288 | return out 289 | } 290 | `, 291 | "intersperse.go": ` 292 | // Intersperse inserts the receiving value between each element of the method receiver. 293 | // Can be generated for any type. 294 | func (s SliceType) Intersperse(value ElementType) (out SliceType) { 295 | for i, el := range s { 296 | out = append(out, el) 297 | if i == len(s)-1 { 298 | break 299 | } 300 | out = append(out, value) 301 | } 302 | return 303 | } 304 | `, 305 | "isprefixof.go": ` 306 | // IsPrefixOf returns true if the current sliceType is a prefix of the passed one. 307 | // Can be generated for any time. 308 | func (s SliceType) IsPrefixOf(in SliceType) bool { 309 | if len(s) > len(in) { 310 | return false 311 | } 312 | for i, v := range s { 313 | if in[i] != v { 314 | return false 315 | } 316 | } 317 | return true 318 | } 319 | `, 320 | "last.go": ` 321 | // Last returns the last element in the slice 322 | // If no element is found, returns the zero-value of the type 323 | // Can be generated for any type. 324 | func (s SliceType) Last() (out ElementType) { 325 | if len(s) > 0 { 326 | out = s[len(s)-1] 327 | } 328 | return 329 | } 330 | `, 331 | "length.go": ` 332 | // Length returns the length (len) of a slice. 333 | // Can be generated for any type. 334 | func (s SliceType) Length() int { 335 | return len(s) 336 | } 337 | `, 338 | "map.go": ` 339 | // Map return a new slice with the map operation applied to each element. 340 | // Can be generated for any type. 341 | func (s SliceType) Map(f func(ElementType) ElementType) (out SliceType) { 342 | if f == nil { 343 | return s 344 | } 345 | for _, v := range s { 346 | out = append(out, f(v)) 347 | } 348 | return 349 | } 350 | `, 351 | "maximum.go": ` 352 | // Maximum returns the maximum in a slice. 353 | // Can be generated for number types. 354 | func (s SliceType) Maximum() (out ElementType) { 355 | if len(s) == 0 { 356 | return 357 | } 358 | for _, i := range s { 359 | if i > out { 360 | out = i 361 | } 362 | } 363 | return 364 | } 365 | `, 366 | "maximumby.go": ` 367 | // MaximumBy returns the maximum elements according to a custom comparator. 368 | // Can be generated for any type. 369 | func (s SliceType) MaximumBy(f func(e1, e2 ElementType) ElementType) (max ElementType) { 370 | if len(s) == 0 { 371 | return 372 | } 373 | max = s[0] 374 | for _, el := range s[1:] { 375 | max = f(max, el) 376 | } 377 | return 378 | } 379 | `, 380 | "minimum.go": ` 381 | // Minimum returns the minimum of a slice. 382 | // Can be generated for number types. 383 | func (s SliceType) Minimum() ElementType { 384 | if len(s) == 0 { 385 | return 0 // bit strange? 386 | } 387 | min := s[0] 388 | for _, i := range s { 389 | if i < min { 390 | min = i 391 | } 392 | } 393 | return min 394 | } 395 | `, 396 | "modes.go": ` 397 | // Modes returns the elements with highest frequency in the slice. 398 | // Can be generated for any type. 399 | func (s SliceType) Modes() (out SliceType) { 400 | if len(s) == 0 { 401 | return 402 | } 403 | 404 | counts := make(map[ElementType]int) 405 | for _, v := range s { 406 | counts[v]++ 407 | } 408 | 409 | var max int 410 | for _, v := range counts { 411 | if v > max { 412 | max = v 413 | } 414 | } 415 | 416 | for k, v := range counts { 417 | if v == max { 418 | out = append(out, k) 419 | } 420 | } 421 | 422 | return 423 | } 424 | `, 425 | "nub.go": ` 426 | // Nub returns a slice containing only the unique elements of the receiver. 427 | // The order of the elements is preserved. 428 | // Can be generated for any type. 429 | func (s SliceType) Nub() (out SliceType) { 430 | if len(s) == 0 { 431 | return 432 | } 433 | 434 | contains := make(map[ElementType]struct{}) 435 | for _, v := range s { 436 | if _, ok := contains[v]; !ok { 437 | contains[v] = struct{}{} 438 | out = append(out, v) 439 | } 440 | } 441 | return 442 | } 443 | `, 444 | "null.go": ` 445 | // Null returns true the slice is empty. 446 | // Can be generated for any type. 447 | func (s SliceType) Null() bool { 448 | return len(s) == 0 449 | } 450 | `, 451 | "product.go": ` 452 | // Product returns the product of all elements in the slice. 453 | // Can be generated for any number type. 454 | func (s SliceType) Product() ElementType { 455 | var prod ElementType 456 | for _, v := range s { 457 | prod += v 458 | } 459 | return prod 460 | } 461 | `, 462 | "reverse.go": ` 463 | // Reverse returns the reversed slice. 464 | // Can be generated for any type. 465 | func (s SliceType) Reverse() (out SliceType) { 466 | for i := len(s) - 1; i >= 0; i-- { 467 | out = append(out, s[i]) 468 | } 469 | return 470 | } 471 | `, 472 | "scanl.go": ` 473 | // Scanl reduces a list by iteratively applying f from left->right and then returns each iteration in a slice. 474 | func (s SliceType) Scanl(e ElementType, f func(e1, e2 ElementType) ElementType) (out SliceType) { 475 | if len(s) == 0 { 476 | return 477 | } 478 | 479 | out = append(out, e) 480 | last := e 481 | 482 | for _, v := range s { 483 | last = f(last, v) 484 | out = append(out, last) 485 | } 486 | 487 | return 488 | } 489 | `, 490 | "sort.go": ` 491 | import ( 492 | "sort" 493 | ) 494 | 495 | // Sort is a wrapper around go sort function. 496 | // Can be generated for any type. 497 | func (s SliceType) Sort() SliceType { 498 | out := make(SliceType, len(s)) 499 | copy(out, s) 500 | sort.Slice(out, func(i, j int) bool { 501 | return out[i] < out[j] 502 | }) 503 | return out 504 | } 505 | `, 506 | "span.go": ` 507 | // Span returns a tuple of any elements that satisfy the predicate up until the first failure, followed by 508 | // the rest of the elements. 509 | // Can be generated for any type. 510 | func (s SliceType) Span(f func(ElementType) bool) (before SliceType, after SliceType) { 511 | if f == nil { 512 | return before, s 513 | } 514 | 515 | failed := false 516 | 517 | for _, v := range s { 518 | if failed || !f(v) { 519 | after = append(after, v) 520 | failed = true 521 | } else { 522 | before = append(before, v) 523 | } 524 | } 525 | 526 | return 527 | } 528 | `, 529 | "splitat.go": ` 530 | // SplitAt splits the slice at the given index, returning before and after as a tuple. 531 | // Can be generated for any type. 532 | func (s SliceType) SplitAt(i int) (before, after SliceType) { 533 | for k, v := range s { 534 | if k < i { 535 | before = append(before, v) 536 | } else { 537 | after = append(after, v) 538 | } 539 | } 540 | return 541 | } 542 | `, 543 | "sum.go": ` 544 | // Sum returns the sum of all elements in the slice. 545 | // Can be generated for any number type. 546 | func (s SliceType) Sum() ElementType { 547 | var sum ElementType 548 | for _, v := range s { 549 | sum += v 550 | } 551 | return sum 552 | } 553 | `, 554 | "tail.go": ` 555 | // Tail takes [1 -> n] elements from a slice, where n = len(list) 556 | // Returns an empty slice if there are less than 2 elements in slice 557 | // Can be generated for any type. 558 | func (s SliceType) Tail() (out SliceType) { 559 | if len(s) <= 1 { 560 | return 561 | } 562 | slicecopy := append([]ElementType(nil), s...) 563 | return slicecopy[1:] 564 | } 565 | `, 566 | "tails.go": ` 567 | // Tails returns all tails of a sequence, in order of large to small, as if it were called recursively. 568 | // Can be generated for any type. 569 | func (s SliceType) Tails() (out SliceSliceType) { 570 | slicecopy := append([]ElementType(nil), s...) 571 | for range s { 572 | out = append(out, slicecopy) 573 | slicecopy = slicecopy[1:] 574 | } 575 | out = append(out, make(SliceType, 0)) 576 | return 577 | } 578 | `, 579 | "take.go": ` 580 | // Take takes the first n elements of the slice, or the entire slice if n > len(slice). 581 | // Can be generated for any type. 582 | func (s SliceType) Take(n uint64) (out SliceType) { 583 | if len(s) == 0 { 584 | return 585 | } 586 | out = make(SliceType, len(s)) 587 | copy(out, s) 588 | if n < uint64(len(s)) { 589 | return out[:n] 590 | } 591 | return 592 | } 593 | `, 594 | "takewhile.go": ` 595 | // TakeWhile continues appending to the output as long as the predicate is satisfied. 596 | // Can be generated for any type. 597 | func (s SliceType) TakeWhile(p func(ElementType) bool) (out SliceType) { 598 | if len(s) == 0 { 599 | return 600 | } 601 | for _, e := range s { 602 | if !p(e) { 603 | return 604 | } 605 | out = append(out, e) 606 | } 607 | return 608 | } 609 | `, 610 | "uncons.go": ` 611 | // Uncons decomposes a slice into the head and tail component. 612 | // Can be generated for any type. 613 | func (s SliceType) Uncons() (head ElementType, tail SliceType) { 614 | return s.Head(), s.Tail() 615 | } 616 | `, 617 | "unlines.go": ` 618 | import ( 619 | "fmt" 620 | ) 621 | 622 | // Unlines joins together the string representation of the slice with newlines after each element. 623 | // Can be generated for any type. 624 | func (s SliceType) Unlines() (out string) { 625 | for i, v := range s { 626 | out += fmt.Sprintf("%v", v) 627 | if i != len(s)-1 { 628 | out += "\n" 629 | } 630 | } 631 | return 632 | } 633 | `, 634 | "unwords.go": ` 635 | import ( 636 | "fmt" 637 | ) 638 | 639 | // Unwords joins together the string representation of the slice with newlines after each element. 640 | // Can be generated for any type. 641 | func (s SliceType) Unwords() (out string) { 642 | for i, v := range s { 643 | out += fmt.Sprintf("%v", v) 644 | if i != len(s)-1 { 645 | out += " " 646 | } 647 | } 648 | return 649 | } 650 | `, 651 | } 652 | 653 | const ( 654 | ForNumbers = "ForNumbers" 655 | ForStrings = "ForStrings" 656 | ForStructs = "ForStructs" 657 | ) 658 | 659 | var funcDomains = map[string][]string{ 660 | "abs.go": {ForNumbers}, 661 | "all.go": {ForNumbers, ForStrings, ForStructs}, 662 | "any.go": {ForNumbers, ForStrings, ForStructs}, 663 | "average.go": {ForNumbers}, 664 | "break.go": {ForNumbers, ForStrings, ForStructs}, 665 | "delete.go": {ForNumbers, ForStrings, ForStructs}, 666 | "drop.go": {ForNumbers, ForStrings, ForStructs}, 667 | "dropwhile.go": {ForNumbers, ForStrings, ForStructs}, 668 | "elem.go": {ForNumbers, ForStrings, ForStructs}, 669 | "filter.go": {ForNumbers, ForStrings, ForStructs}, 670 | "foldl.go": {ForNumbers, ForStrings, ForStructs}, 671 | "foldl1.go": {ForNumbers, ForStrings, ForStructs}, 672 | "foldr.go": {ForNumbers, ForStrings, ForStructs}, 673 | "foldr1.go": {ForNumbers, ForStrings, ForStructs}, 674 | "group.go": {ForNumbers, ForStrings, ForStructs}, 675 | "head.go": {ForNumbers, ForStrings, ForStructs}, 676 | "init.go": {ForNumbers, ForStrings, ForStructs}, 677 | "inits.go": {ForNumbers, ForStrings, ForStructs}, 678 | "intercalate.go": {ForNumbers, ForStrings, ForStructs}, 679 | "intersperse.go": {ForNumbers, ForStrings, ForStructs}, 680 | "isprefixof.go": {ForNumbers, ForStrings, ForStructs}, 681 | "last.go": {ForNumbers, ForStrings, ForStructs}, 682 | "length.go": {ForNumbers, ForStrings, ForStructs}, 683 | "map.go": {ForNumbers, ForStrings, ForStructs}, 684 | "maximum.go": {ForNumbers}, 685 | "maximumby.go": {ForNumbers, ForStrings, ForStructs}, 686 | "minimum.go": {ForNumbers}, 687 | "modes.go": {ForNumbers, ForStrings, ForStructs}, 688 | "nub.go": {ForNumbers, ForStrings, ForStructs}, 689 | "null.go": {ForNumbers, ForStrings, ForStructs}, 690 | "product.go": {ForNumbers}, 691 | "reverse.go": {ForNumbers, ForStrings, ForStructs}, 692 | "scanl.go": {ForNumbers, ForStrings, ForStructs}, 693 | "sort.go": {ForNumbers, ForStrings}, 694 | "span.go": {ForNumbers, ForStrings, ForStructs}, 695 | "splitat.go": {ForNumbers, ForStrings, ForStructs}, 696 | "sum.go": {ForNumbers, ForStrings}, 697 | "tail.go": {ForNumbers, ForStrings, ForStructs}, 698 | "tails.go": {ForNumbers, ForStrings, ForStructs}, 699 | "take.go": {ForNumbers, ForStrings, ForStructs}, 700 | "takewhile.go": {ForNumbers, ForStrings, ForStructs}, 701 | "uncons.go": {ForNumbers, ForStrings, ForStructs}, 702 | "unlines.go": {ForNumbers, ForStrings, ForStructs}, 703 | "unwords.go": {ForNumbers, ForStrings, ForStructs}, 704 | } 705 | -------------------------------------------------------------------------------- /types/Bools.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // Bools represents an array of booleans 4 | type Bools []bool 5 | 6 | // And returns true if all bools are true 7 | func (bs Bools) And() bool { 8 | if len(bs) == 0 { 9 | return true 10 | } 11 | for _, b := range bs { 12 | if !b { 13 | return false 14 | } 15 | } 16 | return true 17 | } 18 | 19 | // Or returns true if any value is true 20 | func (bs Bools) Or() bool { 21 | if len(bs) == 0 { 22 | return true 23 | } 24 | for _, b := range bs { 25 | if b { 26 | return true 27 | } 28 | } 29 | return false 30 | } 31 | -------------------------------------------------------------------------------- /types/Bools_test.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | var ( 8 | boolsTests = []struct { 9 | input Bools 10 | and bool 11 | or bool 12 | }{ 13 | { 14 | nil, 15 | true, 16 | true, 17 | }, 18 | { 19 | Bools{true, true}, 20 | true, 21 | true, 22 | }, 23 | { 24 | Bools{}, 25 | true, 26 | true, 27 | }, 28 | { 29 | Bools{false}, 30 | false, 31 | false, 32 | }, 33 | { 34 | Bools{false, true, false}, 35 | false, 36 | true, 37 | }, 38 | } 39 | ) 40 | 41 | func Test_BoolsAnd(t *testing.T) { 42 | for _, test := range boolsTests { 43 | t.Run("", func(t *testing.T) { 44 | if res := test.input.And(); res != test.and { 45 | t.Errorf("expected %v but got %v", test.and, res) 46 | } 47 | }) 48 | } 49 | } 50 | 51 | func Test_BoolsOr(t *testing.T) { 52 | for _, test := range boolsTests { 53 | t.Run("", func(t *testing.T) { 54 | if res := test.input.Or(); res != test.or { 55 | t.Errorf("expected %v but got %v", test.or, res) 56 | 57 | } 58 | }) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /types/Ints.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // Int is a wrapper around int64 4 | //go:generate hasgo -T=int64 -S=Ints 5 | type Int int64 6 | 7 | // Ints is a wrapper around []int64 8 | type Ints []int64 9 | 10 | // IntReplicate creates a slice with `value` repeated `count` times 11 | func IntReplicate(count uint64, value int64) (out Ints) { 12 | out = make(Ints, count) 13 | for i := uint64(0); i < count; i++ { 14 | out[i] = value 15 | } 16 | return 17 | } 18 | 19 | // IntRange creates a range similar to list comprehension in Haskell 20 | // Ranges in Haskell are _inclusive_ on both bounds. 21 | // IntRange(0,10) == [0..10] == []int{0,1,2,3,4,5,6,7,8,9,10} 22 | func IntRange(start, stop int64) Ints { 23 | if stop-start <= 0 { 24 | return Ints{} 25 | } 26 | out := make(Ints, (stop-start)+1) 27 | var i int 28 | for start <= stop { 29 | out[i] = start 30 | i++ 31 | start++ 32 | } 33 | return out 34 | } 35 | 36 | // EqualsOrdered verifies that the elements in the slices are equal (same position) 37 | func (is Ints) EqualsOrdered(other Ints) bool { 38 | if len(is) != len(other) { 39 | return false 40 | } 41 | for i := range is { 42 | if is[i] != other[i] { 43 | return false 44 | } 45 | } 46 | return true 47 | } 48 | 49 | // Equals verifies that both slices have the same elements, ignoring their position. 50 | func (is Ints) Equals(other Ints) bool { 51 | if len(is) != len(other) { 52 | return false 53 | } 54 | contains := make(map[int64]struct{}, 0) 55 | for _, i := range is { 56 | contains[i] = struct{}{} 57 | } 58 | for _, i := range other { 59 | if _, ok := contains[i]; !ok { 60 | return false 61 | } 62 | } 63 | return true 64 | } 65 | -------------------------------------------------------------------------------- /types/Ints_hasgo.go: -------------------------------------------------------------------------------- 1 | // Package types contains code generated by hasgo. [DO NOT EDIT!] 2 | package types 3 | 4 | import ( 5 | "fmt" 6 | "math" 7 | "sort" 8 | ) 9 | 10 | // =============== abs.go ================= 11 | 12 | // Abs returns the absolute value of all elements in the slice. 13 | // Can be generated for number-types. 14 | func (s Ints) Abs() (out Ints) { 15 | for _, v := range s { 16 | out = append(out, int64(math.Abs(float64(v)))) 17 | } 18 | return 19 | } 20 | 21 | // =============== all.go ================= 22 | 23 | // All returns true if all elements of the slice satisfy the predicate. 24 | // Can be generated for any type. 25 | func (s Ints) All(f func(int64) bool) bool { 26 | if f == nil { 27 | return false 28 | } 29 | for _, v := range s { 30 | if !f(v) { 31 | return false 32 | } 33 | } 34 | return true 35 | } 36 | 37 | // =============== any.go ================= 38 | 39 | // Any returns true if any of the elements satisfy the predicate. 40 | // Can be generated for any type. 41 | func (s Ints) Any(f func(int64) bool) bool { 42 | if f == nil { 43 | return false 44 | } 45 | for _, v := range s { 46 | if f(v) { 47 | return true 48 | } 49 | } 50 | return false 51 | } 52 | 53 | // =============== average.go ================= 54 | 55 | // Average returns the average of all elements in the slice. 56 | // Can be generated for all number types. 57 | func (s Ints) Average() float64 { 58 | var sum int64 59 | if len(s) == 0 { 60 | return float64(0) 61 | } 62 | for _, i := range s { 63 | sum += i 64 | } 65 | return float64(sum) / float64(len(s)) 66 | } 67 | 68 | // =============== break.go ================= 69 | 70 | // Break returns a tuple of any elements that do not satisfy the predicate up until the first time it passes, followed 71 | // by the rest of the elements. 72 | // Can be generated on any type. 73 | func (s Ints) Break(f func(int64) bool) (before Ints, after Ints) { 74 | if f == nil { 75 | return before, s 76 | } 77 | 78 | passed := false 79 | 80 | for _, v := range s { 81 | if passed || f(v) { 82 | after = append(after, v) 83 | passed = true 84 | } else { 85 | before = append(before, v) 86 | } 87 | } 88 | 89 | return 90 | } 91 | 92 | // =============== delete.go ================= 93 | 94 | // Delete returns a slice with the first matching element 95 | // removed from the slice. 96 | // Can be generated for any type. 97 | func (s Ints) Delete(e int64) (out Ints) { 98 | deleted := false 99 | for _, v := range s { 100 | if deleted || v != e { 101 | out = append(out, v) 102 | } else { 103 | deleted = true 104 | } 105 | } 106 | return 107 | } 108 | 109 | // =============== drop.go ================= 110 | 111 | // Drop returns a new Slice with the elements after the provided key. 112 | // Can be generated for any type. 113 | func (s Ints) Drop(i int) (out Ints) { 114 | for i < len(s) { 115 | out = append(out, s[i]) 116 | i++ 117 | } 118 | return 119 | } 120 | 121 | // =============== dropwhile.go ================= 122 | 123 | // DropWhile returns a new slice containing all elements after the predicate fails for the first time. 124 | // Can be generated for any type. 125 | func (s Ints) DropWhile(f func(int64) bool) (out Ints) { 126 | if f == nil { 127 | return s 128 | } 129 | failed := false 130 | for _, v := range s { 131 | if failed { 132 | out = append(out, v) 133 | continue 134 | } 135 | if !f(v) { 136 | out = append(out, v) 137 | failed = true 138 | } 139 | } 140 | return 141 | } 142 | 143 | // =============== elem.go ================= 144 | 145 | // Elem returns true if the slice contains the element 146 | // Can be generated for any type. 147 | func (s Ints) Elem(el int64) bool { 148 | for _, e := range s { 149 | if e == el { 150 | return true 151 | } 152 | } 153 | return false 154 | } 155 | 156 | // =============== filter.go ================= 157 | 158 | // Filter returns a slice containing only the elements that match the predicate. 159 | // Can be generated for any type. 160 | func (s Ints) Filter(f func(int64) bool) (out Ints) { 161 | for _, v := range s { 162 | if f(v) { 163 | out = append(out, v) 164 | } 165 | } 166 | return 167 | } 168 | 169 | // =============== foldl.go ================= 170 | 171 | // Foldl reduces a list by iteratively applying f from left->right. Thus, for an empty slice, the result is the default zero-value. 172 | func (s Ints) Foldl(z int64, f func(e1, e2 int64) int64) (out int64) { 173 | if len(s) == 0 { 174 | return 175 | } 176 | out = f(z, s[0]) 177 | for _, v := range s[1:] { 178 | out = f(out, v) 179 | } 180 | return 181 | } 182 | 183 | // =============== foldl1.go ================= 184 | 185 | // Foldl1 reduces a list by iteratively applying f from left->right. Thus, for an empty slice, the result is the default zero-value. 186 | func (s Ints) Foldl1(f func(e1, e2 int64) int64) (out int64) { 187 | if len(s) == 0 { 188 | return 189 | } 190 | out = s[0] 191 | for _, v := range s[1:] { 192 | out = f(out, v) 193 | } 194 | return 195 | } 196 | 197 | // =============== foldr.go ================= 198 | 199 | // Foldr reduces a list by iteratively applying f from right -> left. Thus, for an empty slice, the result is the default zero-value. 200 | func (s Ints) Foldr(e int64, f func(e1, e2 int64) int64) (out int64) { 201 | if len(s) == 0 { 202 | return 203 | } 204 | 205 | end := len(s) - 1 206 | out = f(s[end], e) 207 | 208 | for i := end - 1; i >= 0; i-- { 209 | out = f(s[i], out) 210 | } 211 | 212 | return 213 | } 214 | 215 | // =============== foldr1.go ================= 216 | 217 | // Foldr1 reduces a list by iteratively applying f from right -> left. Thus, for an empty slice, the result is the default zero-value. 218 | func (s Ints) Foldr1(f func(e1, e2 int64) int64) (out int64) { 219 | if len(s) == 0 { 220 | return 221 | } 222 | 223 | end := len(s) - 1 224 | out = s[end] 225 | 226 | for i := end - 1; i >= 0; i-- { 227 | out = f(s[i], out) 228 | } 229 | 230 | return 231 | } 232 | 233 | // =============== group.go ================= 234 | 235 | // Group returns a list of lists where each list contains only equal elements and the concatenation of the 236 | // result is equal to the argument. 237 | // Can be generated for any type. 238 | func (s Ints) Group() (out [][]int64) { 239 | current := Ints{} 240 | 241 | for i, v := range s { 242 | current = append(current, v) 243 | if i == len(s)-1 || v != s[i+1] { 244 | out = append(out, current) 245 | current = Ints{} 246 | } 247 | } 248 | 249 | return 250 | } 251 | 252 | // =============== head.go ================= 253 | 254 | // Head returns the first element in the slice. 255 | // If no element is found, returns the zero-value of the type. 256 | // Can be generated for any type. 257 | func (s Ints) Head() (out int64) { 258 | if len(s) > 0 { 259 | out = s[0] 260 | } 261 | return 262 | } 263 | 264 | // =============== init.go ================= 265 | 266 | // Init takes n-1 elements from a slice, where n = len(list). 267 | // Can be generated for any type. 268 | func (s Ints) Init() (out Ints) { 269 | if len(s) == 0 { 270 | return 271 | } 272 | slicecopy := append([]int64(nil), s...) 273 | return slicecopy[:len(s)-1] 274 | } 275 | 276 | // =============== inits.go ================= 277 | 278 | // Inits returns all inits of a sequence, in order of small to large, as if it were called recursively. 279 | // Can be generated for any type. 280 | func (s Ints) Inits() (out [][]int64) { 281 | out = append(out, make(Ints, 0)) 282 | for i := range s { 283 | init := make(Ints, i+1) 284 | for n := 0; n <= i; n++ { 285 | init[n] = s[n] 286 | } 287 | out = append(out, init) 288 | } 289 | return 290 | } 291 | 292 | // =============== intercalate.go ================= 293 | 294 | // Intercalate inserts the method receiver slice into the function slice at each step. 295 | // Can be generated for any type. 296 | func (s Ints) Intercalate(ss [][]int64) (out Ints) { 297 | for i, slice := range ss { 298 | for _, el := range slice { 299 | out = append(out, el) 300 | } 301 | if i == len(ss)-1 { 302 | break 303 | } 304 | for _, el := range s { 305 | out = append(out, el) 306 | } 307 | } 308 | return out 309 | } 310 | 311 | // =============== intersperse.go ================= 312 | 313 | // Intersperse inserts the receiving value between each element of the method receiver. 314 | // Can be generated for any type. 315 | func (s Ints) Intersperse(value int64) (out Ints) { 316 | for i, el := range s { 317 | out = append(out, el) 318 | if i == len(s)-1 { 319 | break 320 | } 321 | out = append(out, value) 322 | } 323 | return 324 | } 325 | 326 | // =============== isprefixof.go ================= 327 | 328 | // IsPrefixOf returns true if the current sliceType is a prefix of the passed one. 329 | // Can be generated for any time. 330 | func (s Ints) IsPrefixOf(in Ints) bool { 331 | if len(s) > len(in) { 332 | return false 333 | } 334 | for i, v := range s { 335 | if in[i] != v { 336 | return false 337 | } 338 | } 339 | return true 340 | } 341 | 342 | // =============== last.go ================= 343 | 344 | // Last returns the last element in the slice 345 | // If no element is found, returns the zero-value of the type 346 | // Can be generated for any type. 347 | func (s Ints) Last() (out int64) { 348 | if len(s) > 0 { 349 | out = s[len(s)-1] 350 | } 351 | return 352 | } 353 | 354 | // =============== length.go ================= 355 | 356 | // Length returns the length (len) of a slice. 357 | // Can be generated for any type. 358 | func (s Ints) Length() int { 359 | return len(s) 360 | } 361 | 362 | // =============== map.go ================= 363 | 364 | // Map return a new slice with the map operation applied to each element. 365 | // Can be generated for any type. 366 | func (s Ints) Map(f func(int64) int64) (out Ints) { 367 | if f == nil { 368 | return s 369 | } 370 | for _, v := range s { 371 | out = append(out, f(v)) 372 | } 373 | return 374 | } 375 | 376 | // =============== maximum.go ================= 377 | 378 | // Maximum returns the maximum in a slice. 379 | // Can be generated for number types. 380 | func (s Ints) Maximum() (out int64) { 381 | if len(s) == 0 { 382 | return 383 | } 384 | for _, i := range s { 385 | if i > out { 386 | out = i 387 | } 388 | } 389 | return 390 | } 391 | 392 | // =============== maximumby.go ================= 393 | 394 | // MaximumBy returns the maximum elements according to a custom comparator. 395 | // Can be generated for any type. 396 | func (s Ints) MaximumBy(f func(e1, e2 int64) int64) (max int64) { 397 | if len(s) == 0 { 398 | return 399 | } 400 | max = s[0] 401 | for _, el := range s[1:] { 402 | max = f(max, el) 403 | } 404 | return 405 | } 406 | 407 | // =============== minimum.go ================= 408 | 409 | // Minimum returns the minimum of a slice. 410 | // Can be generated for number types. 411 | func (s Ints) Minimum() int64 { 412 | if len(s) == 0 { 413 | return 0 // bit strange? 414 | } 415 | min := s[0] 416 | for _, i := range s { 417 | if i < min { 418 | min = i 419 | } 420 | } 421 | return min 422 | } 423 | 424 | // =============== modes.go ================= 425 | 426 | // Modes returns the elements with highest frequency in the slice. 427 | // Can be generated for any type. 428 | func (s Ints) Modes() (out Ints) { 429 | if len(s) == 0 { 430 | return 431 | } 432 | 433 | counts := make(map[int64]int) 434 | for _, v := range s { 435 | counts[v]++ 436 | } 437 | 438 | var max int 439 | for _, v := range counts { 440 | if v > max { 441 | max = v 442 | } 443 | } 444 | 445 | for k, v := range counts { 446 | if v == max { 447 | out = append(out, k) 448 | } 449 | } 450 | 451 | return 452 | } 453 | 454 | // =============== nub.go ================= 455 | 456 | // Nub returns a slice containing only the unique elements of the receiver. 457 | // The order of the elements is preserved. 458 | // Can be generated for any type. 459 | func (s Ints) Nub() (out Ints) { 460 | if len(s) == 0 { 461 | return 462 | } 463 | 464 | contains := make(map[int64]struct{}) 465 | for _, v := range s { 466 | if _, ok := contains[v]; !ok { 467 | contains[v] = struct{}{} 468 | out = append(out, v) 469 | } 470 | } 471 | return 472 | } 473 | 474 | // =============== null.go ================= 475 | 476 | // Null returns true the slice is empty. 477 | // Can be generated for any type. 478 | func (s Ints) Null() bool { 479 | return len(s) == 0 480 | } 481 | 482 | // =============== product.go ================= 483 | 484 | // Product returns the product of all elements in the slice. 485 | // Can be generated for any number type. 486 | func (s Ints) Product() int64 { 487 | var prod int64 488 | for _, v := range s { 489 | prod += v 490 | } 491 | return prod 492 | } 493 | 494 | // =============== reverse.go ================= 495 | 496 | // Reverse returns the reversed slice. 497 | // Can be generated for any type. 498 | func (s Ints) Reverse() (out Ints) { 499 | for i := len(s) - 1; i >= 0; i-- { 500 | out = append(out, s[i]) 501 | } 502 | return 503 | } 504 | 505 | // =============== scanl.go ================= 506 | 507 | // Scanl reduces a list by iteratively applying f from left->right and then returns each iteration in a slice. 508 | func (s Ints) Scanl(e int64, f func(e1, e2 int64) int64) (out Ints) { 509 | if len(s) == 0 { 510 | return 511 | } 512 | 513 | out = append(out, e) 514 | last := e 515 | 516 | for _, v := range s { 517 | last = f(last, v) 518 | out = append(out, last) 519 | } 520 | 521 | return 522 | } 523 | 524 | // =============== sort.go ================= 525 | 526 | // Sort is a wrapper around go sort function. 527 | // Can be generated for any type. 528 | func (s Ints) Sort() Ints { 529 | out := make(Ints, len(s)) 530 | copy(out, s) 531 | sort.Slice(out, func(i, j int) bool { 532 | return out[i] < out[j] 533 | }) 534 | return out 535 | } 536 | 537 | // =============== span.go ================= 538 | 539 | // Span returns a tuple of any elements that satisfy the predicate up until the first failure, followed by 540 | // the rest of the elements. 541 | // Can be generated for any type. 542 | func (s Ints) Span(f func(int64) bool) (before Ints, after Ints) { 543 | if f == nil { 544 | return before, s 545 | } 546 | 547 | failed := false 548 | 549 | for _, v := range s { 550 | if failed || !f(v) { 551 | after = append(after, v) 552 | failed = true 553 | } else { 554 | before = append(before, v) 555 | } 556 | } 557 | 558 | return 559 | } 560 | 561 | // =============== splitat.go ================= 562 | 563 | // SplitAt splits the slice at the given index, returning before and after as a tuple. 564 | // Can be generated for any type. 565 | func (s Ints) SplitAt(i int) (before, after Ints) { 566 | for k, v := range s { 567 | if k < i { 568 | before = append(before, v) 569 | } else { 570 | after = append(after, v) 571 | } 572 | } 573 | return 574 | } 575 | 576 | // =============== sum.go ================= 577 | 578 | // Sum returns the sum of all elements in the slice. 579 | // Can be generated for any number type. 580 | func (s Ints) Sum() int64 { 581 | var sum int64 582 | for _, v := range s { 583 | sum += v 584 | } 585 | return sum 586 | } 587 | 588 | // =============== tail.go ================= 589 | 590 | // Tail takes [1 -> n] elements from a slice, where n = len(list) 591 | // Returns an empty slice if there are less than 2 elements in slice 592 | // Can be generated for any type. 593 | func (s Ints) Tail() (out Ints) { 594 | if len(s) <= 1 { 595 | return 596 | } 597 | slicecopy := append([]int64(nil), s...) 598 | return slicecopy[1:] 599 | } 600 | 601 | // =============== tails.go ================= 602 | 603 | // Tails returns all tails of a sequence, in order of large to small, as if it were called recursively. 604 | // Can be generated for any type. 605 | func (s Ints) Tails() (out [][]int64) { 606 | slicecopy := append([]int64(nil), s...) 607 | for range s { 608 | out = append(out, slicecopy) 609 | slicecopy = slicecopy[1:] 610 | } 611 | out = append(out, make(Ints, 0)) 612 | return 613 | } 614 | 615 | // =============== take.go ================= 616 | 617 | // Take takes the first n elements of the slice, or the entire slice if n > len(slice). 618 | // Can be generated for any type. 619 | func (s Ints) Take(n uint64) (out Ints) { 620 | if len(s) == 0 { 621 | return 622 | } 623 | out = make(Ints, len(s)) 624 | copy(out, s) 625 | if n < uint64(len(s)) { 626 | return out[:n] 627 | } 628 | return 629 | } 630 | 631 | // =============== takewhile.go ================= 632 | 633 | // TakeWhile continues appending to the output as long as the predicate is satisfied. 634 | // Can be generated for any type. 635 | func (s Ints) TakeWhile(p func(int64) bool) (out Ints) { 636 | if len(s) == 0 { 637 | return 638 | } 639 | for _, e := range s { 640 | if !p(e) { 641 | return 642 | } 643 | out = append(out, e) 644 | } 645 | return 646 | } 647 | 648 | // =============== uncons.go ================= 649 | 650 | // Uncons decomposes a slice into the head and tail component. 651 | // Can be generated for any type. 652 | func (s Ints) Uncons() (head int64, tail Ints) { 653 | return s.Head(), s.Tail() 654 | } 655 | 656 | // =============== unlines.go ================= 657 | 658 | // Unlines joins together the string representation of the slice with newlines after each element. 659 | // Can be generated for any type. 660 | func (s Ints) Unlines() (out string) { 661 | for i, v := range s { 662 | out += fmt.Sprintf("%v", v) 663 | if i != len(s)-1 { 664 | out += "\n" 665 | } 666 | } 667 | return 668 | } 669 | 670 | // =============== unwords.go ================= 671 | 672 | // Unwords joins together the string representation of the slice with newlines after each element. 673 | // Can be generated for any type. 674 | func (s Ints) Unwords() (out string) { 675 | for i, v := range s { 676 | out += fmt.Sprintf("%v", v) 677 | if i != len(s)-1 { 678 | out += " " 679 | } 680 | } 681 | return 682 | } 683 | -------------------------------------------------------------------------------- /types/Ints_test.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | // unit testing the Ints 8 | var ( 9 | intsMathTests = []struct { 10 | input Ints 11 | sum int64 12 | product int64 13 | average float64 14 | }{ 15 | { 16 | nil, 17 | 0, 18 | 0, 19 | 0, 20 | }, 21 | { 22 | Ints{}, 23 | 0, 24 | 0, 25 | 0, 26 | }, 27 | { 28 | Ints([]int64{}), 29 | 0, 30 | 0, 31 | 0, 32 | }, 33 | { 34 | Ints([]int64{1, 2, 3}), 35 | 6, 36 | 6, 37 | 2, 38 | }, 39 | } 40 | 41 | intsFilterTests = []struct { 42 | input Ints 43 | filter func(int64) bool 44 | output Ints 45 | }{ 46 | { 47 | nil, 48 | nil, 49 | Ints{}, 50 | }, 51 | { 52 | Ints{}, 53 | nil, 54 | Ints{}, 55 | }, 56 | { 57 | Ints{1, 2, 3, 4}, 58 | func(i int64) bool { return i%2 == 0 }, 59 | Ints{2, 4}, 60 | }, 61 | } 62 | 63 | intsPredicateTests = []struct { 64 | input Ints 65 | predicate func(int64) bool 66 | any bool 67 | all bool 68 | }{ 69 | { 70 | nil, 71 | nil, 72 | false, 73 | false, 74 | }, 75 | { 76 | Ints{}, 77 | nil, 78 | false, 79 | false, 80 | }, 81 | { 82 | Ints{1, 2, 3, 4}, 83 | func(i int64) bool { return i%2 == 0 }, 84 | true, 85 | false, 86 | }, 87 | { 88 | Ints{2, 4, 6, 8}, 89 | func(i int64) bool { return i%2 == 0 }, 90 | true, 91 | true, 92 | }, 93 | { 94 | Ints{1, 3, 5, 7}, 95 | func(i int64) bool { return i%2 == 0 }, 96 | false, 97 | false, 98 | }, 99 | } 100 | 101 | intsRangeTests = []struct { 102 | start int64 103 | stop int64 104 | output Ints 105 | }{ 106 | {0, 10, Ints{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}}, 107 | {-10, 1, Ints{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1}}, 108 | } 109 | 110 | intsReplicateTests = []struct { 111 | count uint64 112 | value int64 113 | output Ints 114 | }{ 115 | {5, 1337, Ints{1337, 1337, 1337, 1337, 1337}}, 116 | } 117 | 118 | // tests that take a subset of the slice 119 | intsTakeTests = []struct { 120 | input Ints 121 | takeAmount uint64 122 | take Ints 123 | init Ints 124 | tail Ints 125 | head int64 126 | last int64 127 | whilePred func(int64) bool 128 | whileOutput Ints 129 | }{ 130 | { 131 | nil, 132 | 3, 133 | Ints{}, 134 | Ints{}, 135 | Ints{}, 136 | 0, 137 | 0, 138 | nil, 139 | Ints{}, 140 | }, 141 | { 142 | Ints{}, 143 | 3, 144 | Ints{}, 145 | Ints{}, 146 | Ints{}, 147 | 0, 148 | 0, 149 | nil, 150 | Ints{}, 151 | }, 152 | { 153 | IntRange(0, 10), 154 | 3, 155 | Ints{0, 1, 2}, 156 | IntRange(0, 9), 157 | IntRange(1, 10), 158 | 0, 159 | 10, 160 | func(u int64) bool { return u < 5 }, 161 | IntRange(0, 4), 162 | }, 163 | { 164 | IntRange(0, 10), 165 | 11, 166 | IntRange(0, 10), 167 | IntRange(0, 9), 168 | IntRange(1, 10), 169 | 0, 170 | 10, 171 | func(u int64) bool { return u < 100 }, 172 | IntRange(0, 10), 173 | }, 174 | } 175 | 176 | intsReverseTests = []struct { 177 | input Ints 178 | output Ints 179 | }{ 180 | { 181 | Ints{}, 182 | Ints{}, 183 | }, 184 | { 185 | nil, 186 | Ints{}, 187 | }, 188 | { 189 | Ints{1, 2, 3}, 190 | Ints{3, 2, 1}, 191 | }, 192 | } 193 | 194 | intsUnconsTests = []struct { 195 | input Ints 196 | head int64 197 | tail Ints 198 | }{ 199 | { 200 | Ints{1, 2, 3, 4}, 201 | 1, 202 | Ints{2, 3, 4}, 203 | }, 204 | { 205 | Ints{}, 206 | 0, 207 | Ints{}, 208 | }, 209 | { 210 | nil, 211 | 0, 212 | Ints{}, 213 | }, 214 | } 215 | 216 | intsMinMaxTests = []struct { 217 | input Ints 218 | min int64 219 | max int64 220 | }{ 221 | { 222 | nil, 223 | 0, 224 | 0, 225 | }, 226 | { 227 | Ints{}, 228 | 0, 229 | 0, 230 | }, 231 | { 232 | Ints{-1, 5, 3, -100}, 233 | -100, 234 | 5, 235 | }, 236 | } 237 | 238 | intsMinMaxByTests = []struct { 239 | input Ints 240 | comparator func(i1, i2 int64) int64 241 | max int64 242 | }{ 243 | { 244 | nil, 245 | func(i1, i2 int64) int64 { return i1 }, 246 | 0, 247 | }, 248 | { 249 | Ints{}, 250 | func(i1, i2 int64) int64 { return i1 }, 251 | 0, 252 | }, 253 | { 254 | Ints{1, 2, 3, 4}, 255 | func(i1, i2 int64) int64 { 256 | if i1 > i2 { 257 | return i1 258 | } 259 | return i2 260 | }, 261 | 4, 262 | }, 263 | } 264 | 265 | intsMapTests = []struct { 266 | input Ints 267 | mapfunc func(int64) int64 268 | output Ints 269 | }{ 270 | { 271 | nil, 272 | func(i int64) int64 { return i * i }, 273 | Ints{}, 274 | }, 275 | { 276 | Ints{}, 277 | func(i int64) int64 { return i * i }, 278 | Ints{}, 279 | }, 280 | { 281 | Ints{1, 2, 3}, 282 | func(i int64) int64 { return i * i }, 283 | Ints{1, 4, 9}, 284 | }, 285 | { 286 | Ints{1, 2, 3}, 287 | nil, 288 | Ints{1, 2, 3}, 289 | }, 290 | } 291 | 292 | intsSortTests = []struct { 293 | input Ints 294 | output Ints 295 | }{ 296 | { 297 | nil, 298 | Ints{}, 299 | }, 300 | { 301 | Ints{}, 302 | Ints{}, 303 | }, 304 | { 305 | Ints{3, 2, 2, 1}, 306 | Ints{1, 2, 2, 3}, 307 | }, 308 | } 309 | 310 | intsLengthTests = []struct { 311 | input Ints 312 | output int 313 | }{ 314 | { 315 | Ints{1, 2, 3}, 316 | 3, 317 | }, 318 | { 319 | nil, 320 | 0, 321 | }, 322 | { 323 | Ints{}, 324 | 0, 325 | }, 326 | } 327 | 328 | // tests that result in boolean 329 | intsBoolTests = []struct { 330 | input Ints 331 | null bool 332 | }{ 333 | { 334 | nil, 335 | true, 336 | }, 337 | { 338 | Ints{}, 339 | true, 340 | }, 341 | { 342 | Ints{1, 2, 3}, 343 | false, 344 | }, 345 | } 346 | 347 | intsIntersperseTests = []struct { 348 | input Ints 349 | intersperse int64 350 | output Ints 351 | }{ 352 | { 353 | nil, 354 | 0, 355 | Ints{}, 356 | }, 357 | { 358 | nil, 359 | 1337, 360 | Ints{}, 361 | }, 362 | { 363 | Ints{}, 364 | 0, 365 | Ints{}, 366 | }, 367 | { 368 | Ints{1, 2, 3}, 369 | 0, 370 | Ints{1, 0, 2, 0, 3}, 371 | }, 372 | { 373 | Ints{1, 2, 3}, 374 | 1337, 375 | Ints{1, 1337, 2, 1337, 3}, 376 | }, 377 | } 378 | 379 | intsIntercalateTests = []struct { 380 | input Ints 381 | intercalate [][]int64 382 | output Ints 383 | }{ 384 | { 385 | nil, 386 | [][]int64{ 387 | {4, 4}, 388 | {5, 5}, 389 | }, 390 | Ints{4, 4, 5, 5}, 391 | }, 392 | { 393 | Ints{}, 394 | [][]int64{ 395 | {4, 4}, 396 | {5, 5}, 397 | }, 398 | Ints{4, 4, 5, 5}, 399 | }, 400 | { 401 | Ints{1, 2}, 402 | [][]int64{ 403 | {4, 4}, 404 | {5, 5}, 405 | }, 406 | Ints{4, 4, 1, 2, 5, 5}, 407 | }, 408 | { 409 | Ints{1, 2}, 410 | [][]int64{ 411 | {4, 4}, 412 | {5, 5}, 413 | {6, 6}, 414 | }, 415 | Ints{4, 4, 1, 2, 5, 5, 1, 2, 6, 6}, 416 | }, 417 | } 418 | 419 | intsModesTests = []struct { 420 | input Ints 421 | output Ints 422 | }{ 423 | { 424 | nil, 425 | Ints{}, 426 | }, 427 | { 428 | Ints{}, 429 | Ints{}, 430 | }, 431 | { 432 | Ints{1, 2, 3}, 433 | Ints{1, 2, 3}, 434 | }, 435 | { 436 | Ints{1, 1, 2, 2, 3, 3}, 437 | Ints{1, 2, 3}, 438 | }, 439 | { 440 | Ints{1, 2, 2, 3}, 441 | Ints{2}, 442 | }, 443 | { 444 | Ints{1, 2, 2, 3, 3}, 445 | Ints{2, 3}, 446 | }, 447 | } 448 | 449 | intsNubTests = []struct { 450 | input Ints 451 | output Ints 452 | }{ 453 | { 454 | nil, 455 | Ints{}, 456 | }, 457 | { 458 | Ints{}, 459 | Ints{}, 460 | }, 461 | { 462 | Ints{1, 2, 3}, 463 | Ints{1, 2, 3}, 464 | }, 465 | { 466 | Ints{1, 2, 3, 2, 1}, 467 | Ints{1, 2, 3}, 468 | }, 469 | { 470 | Ints{3, 3, 3, 3, 2, 1, 2, 3}, 471 | Ints{3, 2, 1}, 472 | }, 473 | { 474 | Ints{1, 1, 1, 1, 1}, 475 | Ints{1}, 476 | }, 477 | } 478 | 479 | intsStringTests = []struct { 480 | input Ints 481 | unlines string 482 | unwords string 483 | }{ 484 | { 485 | nil, 486 | "", 487 | "", 488 | }, 489 | { 490 | Ints{}, 491 | "", 492 | "", 493 | }, 494 | { 495 | Ints{1, 2, 3}, 496 | "1\n2\n3", 497 | "1 2 3", 498 | }, 499 | } 500 | 501 | intsDeleteTests = []struct { 502 | input Ints 503 | element int64 504 | output Ints 505 | }{ 506 | { 507 | nil, 508 | 0, 509 | Ints{}, 510 | }, 511 | { 512 | Ints{}, 513 | 0, 514 | Ints{}, 515 | }, 516 | { 517 | Ints{1, 2, 3, 3, 4, 5, 3}, 518 | 3, 519 | Ints{1, 2, 3, 4, 5, 3}, 520 | }, 521 | { 522 | Ints{1, 2, 3}, 523 | -1, 524 | Ints{1, 2, 3}, 525 | }, 526 | } 527 | 528 | intsFoldTests = []struct { 529 | input Ints 530 | init int64 531 | foldfunc func(int64, int64) int64 532 | foldl int64 533 | foldl1 int64 534 | foldr int64 535 | foldr1 int64 536 | }{ 537 | { 538 | nil, 539 | 0, 540 | func(i1, i2 int64) int64 { return i1 + i2 }, 541 | 0, 542 | 0, 543 | 0, 544 | 0, 545 | }, 546 | { 547 | Ints{}, 548 | 0, 549 | func(i1, i2 int64) int64 { return i1 + i2 }, 550 | 0, 551 | 0, 552 | 0, 553 | 0, 554 | }, 555 | { 556 | Ints{1}, 557 | 1, 558 | func(i1, i2 int64) int64 { return i1 + i2 }, 559 | 2, 560 | 1, 561 | 2, 562 | 1, 563 | }, 564 | { 565 | Ints{1, 2, 3, 4, 5}, 566 | 0, 567 | func(i1, i2 int64) int64 { return i1 - i2 }, 568 | -15, 569 | -13, 570 | 3, 571 | 3, 572 | }, 573 | } 574 | 575 | intsElemTests = []struct { 576 | input Ints 577 | needle int64 578 | output bool 579 | }{ 580 | { 581 | nil, 582 | 0, 583 | false, 584 | }, 585 | { 586 | Ints{}, 587 | 0, 588 | false, 589 | }, 590 | { 591 | Ints{1, 2, 3, 4}, 592 | 1, 593 | true, 594 | }, 595 | { 596 | Ints{1, 2, 3, 4}, 597 | 100, 598 | false, 599 | }, 600 | } 601 | 602 | intsDropTests = []struct { 603 | input Ints 604 | drop int 605 | output Ints 606 | }{ 607 | { 608 | nil, 609 | 0, 610 | Ints{}, 611 | }, 612 | { 613 | Ints{}, 614 | 0, 615 | Ints{}, 616 | }, 617 | { 618 | Ints{1, 2, 3, 4}, 619 | 5, 620 | Ints{}, 621 | }, 622 | { 623 | Ints{1, 2, 3, 4}, 624 | 1, 625 | Ints{2, 3, 4}, 626 | }, 627 | { 628 | Ints{1, 2, 3, 4}, 629 | 3, 630 | Ints{4}, 631 | }, 632 | } 633 | 634 | intsSpanTests = []struct { 635 | input Ints 636 | spanfunc func(int64) bool 637 | before Ints 638 | after Ints 639 | }{ 640 | { 641 | nil, 642 | func(i int64) bool { return i < 3 }, 643 | Ints{}, 644 | Ints{}, 645 | }, 646 | { 647 | Ints{}, 648 | func(i int64) bool { return i < 3 }, 649 | Ints{}, 650 | Ints{}, 651 | }, 652 | { 653 | Ints{1, 2, 3, 4, 5}, 654 | nil, 655 | Ints{}, 656 | Ints{1, 2, 3, 4, 5}, 657 | }, 658 | { 659 | Ints{1, 2, 3, 4, 5}, 660 | func(i int64) bool { return i < 9 }, 661 | Ints{1, 2, 3, 4, 5}, 662 | Ints{}, 663 | }, 664 | { 665 | Ints{1, 2, 3, 4, 5}, 666 | func(i int64) bool { return i > 9 }, 667 | Ints{}, 668 | Ints{1, 2, 3, 4, 5}, 669 | }, 670 | { 671 | Ints{1, 2, 3, 4, 5}, 672 | func(i int64) bool { return i < 3 }, 673 | Ints{1, 2}, 674 | Ints{3, 4, 5}, 675 | }, 676 | } 677 | 678 | intsDropWhileTests = []struct { 679 | input Ints 680 | dropfunc func(int64) bool 681 | output Ints 682 | }{ 683 | { 684 | nil, 685 | func(i int64) bool { return i < 3 }, 686 | Ints{}, 687 | }, 688 | { 689 | Ints{}, 690 | func(i int64) bool { return i < 3 }, 691 | Ints{}, 692 | }, 693 | { 694 | Ints{1, 2, 3, 4, 5}, 695 | nil, 696 | Ints{1, 2, 3, 4, 5}, 697 | }, 698 | { 699 | Ints{1, 2, 3, 4, 5}, 700 | func(i int64) bool { return i < 10 }, 701 | Ints{}, 702 | }, 703 | { 704 | Ints{1, 2, 3, 4, 5}, 705 | func(i int64) bool { return i < 3 }, 706 | Ints{3, 4, 5}, 707 | }, 708 | { 709 | Ints{1, 2, 3, 4, 3, 2, 1}, 710 | func(i int64) bool { return i < 3 }, 711 | Ints{3, 4, 3, 2, 1}, 712 | }, 713 | } 714 | 715 | intsBreakTests = []struct { 716 | input Ints 717 | breakfunc func(int64) bool 718 | before Ints 719 | after Ints 720 | }{ 721 | { 722 | nil, 723 | func(i int64) bool { return i < 3 }, 724 | Ints{}, 725 | Ints{}, 726 | }, 727 | { 728 | Ints{}, 729 | func(i int64) bool { return i < 3 }, 730 | Ints{}, 731 | Ints{}, 732 | }, 733 | { 734 | Ints{1, 2, 3, 4, 5}, 735 | nil, 736 | Ints{}, 737 | Ints{1, 2, 3, 4, 5}, 738 | }, 739 | { 740 | Ints{1, 2, 3, 4, 5}, 741 | func(i int64) bool { return i < 10 }, 742 | Ints{}, 743 | Ints{1, 2, 3, 4, 5}, 744 | }, 745 | { 746 | Ints{1, 2, 3, 4, 5}, 747 | func(i int64) bool { return i > 10 }, 748 | Ints{1, 2, 3, 4, 5}, 749 | Ints{}, 750 | }, 751 | { 752 | Ints{1, 2, 3, 4, 5}, 753 | func(i int64) bool { return i > 3 }, 754 | Ints{1, 2, 3}, 755 | Ints{4, 5}, 756 | }, 757 | } 758 | 759 | intsInitsTests = []struct { 760 | input Ints 761 | output []Ints 762 | }{ 763 | { 764 | nil, 765 | []Ints{}, 766 | }, 767 | { 768 | Ints{}, 769 | []Ints{}, 770 | }, 771 | { 772 | Ints{1, 2, 3}, 773 | []Ints{ 774 | {}, 775 | {1}, 776 | {1, 2}, 777 | {1, 2, 3}, 778 | }, 779 | }, 780 | } 781 | 782 | intsTailsTests = []struct { 783 | input Ints 784 | output []Ints 785 | }{ 786 | { 787 | nil, 788 | []Ints{}, 789 | }, 790 | { 791 | Ints{}, 792 | []Ints{}, 793 | }, 794 | { 795 | Ints{1, 2, 3}, 796 | []Ints{ 797 | {1, 2, 3}, 798 | {2, 3}, 799 | {3}, 800 | {}, 801 | }, 802 | }, 803 | } 804 | 805 | intsSplitAtTests = []struct { 806 | input Ints 807 | i int 808 | before Ints 809 | after Ints 810 | }{ 811 | { 812 | nil, 813 | 5, 814 | Ints{}, 815 | Ints{}, 816 | }, 817 | { 818 | Ints{}, 819 | 5, 820 | Ints{}, 821 | Ints{}, 822 | }, 823 | { 824 | Ints{1, 2, 3, 4, 5}, 825 | 0, 826 | Ints{}, 827 | Ints{1, 2, 3, 4, 5}, 828 | }, 829 | { 830 | Ints{1, 2, 3, 4, 5}, 831 | -1, 832 | Ints{}, 833 | Ints{1, 2, 3, 4, 5}, 834 | }, 835 | { 836 | Ints{1, 2, 3, 4, 5}, 837 | 10, 838 | Ints{1, 2, 3, 4, 5}, 839 | Ints{}, 840 | }, 841 | { 842 | Ints{1, 2, 3, 4, 5}, 843 | 5, 844 | Ints{1, 2, 3, 4, 5}, 845 | Ints{}, 846 | }, 847 | { 848 | Ints{1, 2, 3, 4, 5}, 849 | 3, 850 | Ints{1, 2, 3}, 851 | Ints{4, 5}, 852 | }, 853 | } 854 | 855 | intsGroupTests = []struct { 856 | input Ints 857 | output []Ints 858 | }{ 859 | { 860 | nil, 861 | []Ints{}, 862 | }, 863 | { 864 | Ints{}, 865 | []Ints{}, 866 | }, 867 | { 868 | Ints{1, 2, 3}, 869 | []Ints{{1}, {2}, {3}}, 870 | }, 871 | { 872 | Ints{1, 2, 2, 2, 3, 3, 4, 5, 5}, 873 | []Ints{{1}, {2, 2, 2}, {3, 3}, {4}, {5, 5}}, 874 | }, 875 | } 876 | 877 | intsScanTests = []struct { 878 | input Ints 879 | init int64 880 | scanfunc func(int64, int64) int64 881 | scanl Ints 882 | }{ 883 | { 884 | nil, 885 | 0, 886 | func(i1, i2 int64) int64 { return i1 + i2 }, 887 | Ints{}, 888 | }, 889 | { 890 | Ints{}, 891 | 0, 892 | func(i1, i2 int64) int64 { return i1 + i2 }, 893 | Ints{}, 894 | }, 895 | { 896 | Ints{1}, 897 | 1, 898 | func(i1, i2 int64) int64 { return i1 + i2 }, 899 | Ints{1, 2}, 900 | }, 901 | { 902 | Ints{1, 2, 3, 4, 5}, 903 | 5, 904 | func(i1, i2 int64) int64 { return i1 + i2 }, 905 | Ints{5, 6, 8, 11, 15, 20}, 906 | }, 907 | } 908 | 909 | intsIsPrefixTests = []struct { 910 | input Ints 911 | param1 Ints 912 | output bool 913 | }{ 914 | { 915 | nil, 916 | Ints{}, 917 | true, 918 | }, 919 | { 920 | Ints{}, 921 | Ints{}, 922 | true, 923 | }, 924 | { 925 | Ints{1, 2, 3}, 926 | Ints{1, 2}, 927 | false, 928 | }, 929 | { 930 | Ints{1, 2, 3}, 931 | Ints{1, 2, 3}, 932 | true, 933 | }, 934 | { 935 | Ints{1, 2, 3}, 936 | Ints{1, 2, 3, 4, 5}, 937 | true, 938 | }, 939 | { 940 | Ints{1, 2, 3}, 941 | Ints{1, 2, 4}, 942 | false, 943 | }, 944 | { 945 | Ints{1, 2, 3}, 946 | Ints{1, 2, 2, 2}, 947 | false, 948 | }, 949 | } 950 | ) 951 | 952 | func Test_IntsSum(t *testing.T) { 953 | for _, test := range intsMathTests { 954 | t.Run("", func(t *testing.T) { 955 | if res := test.input.Sum(); res != test.sum { 956 | t.Errorf("expected %v but got %v", test.sum, res) 957 | } 958 | }) 959 | } 960 | } 961 | 962 | func Test_IntsProduct(t *testing.T) { 963 | for _, test := range intsMathTests { 964 | t.Run("", func(t *testing.T) { 965 | if res := test.input.Product(); res != test.product { 966 | t.Errorf("expected %v but got %v", test.product, res) 967 | } 968 | }) 969 | } 970 | } 971 | 972 | func Test_IntsAverage(t *testing.T) { 973 | for _, test := range intsMathTests { 974 | t.Run("", func(t *testing.T) { 975 | if res := test.input.Average(); res != test.average { 976 | t.Errorf("expected %v but got %v", test.product, res) 977 | } 978 | }) 979 | } 980 | } 981 | 982 | func Test_IntsFilter(t *testing.T) { 983 | for _, test := range intsFilterTests { 984 | t.Run("", func(t *testing.T) { 985 | if res := test.input.Filter(test.filter); !res.Equals(test.output) { 986 | t.Errorf("expected %v but got %v", test.output, res) 987 | } 988 | }) 989 | } 990 | } 991 | 992 | func Test_IntsAll(t *testing.T) { 993 | for _, test := range intsPredicateTests { 994 | t.Run("", func(t *testing.T) { 995 | if res := test.input.All(test.predicate); res != test.all { 996 | t.Errorf("expected %v but got %v", test.all, res) 997 | } 998 | }) 999 | } 1000 | } 1001 | 1002 | func Test_IntsAny(t *testing.T) { 1003 | for _, test := range intsPredicateTests { 1004 | t.Run("", func(t *testing.T) { 1005 | if res := test.input.Any(test.predicate); res != test.any { 1006 | t.Errorf("expected %v but got %v", test.any, res) 1007 | } 1008 | }) 1009 | } 1010 | } 1011 | 1012 | func Test_IntsRange(t *testing.T) { 1013 | for _, test := range intsRangeTests { 1014 | t.Run("", func(t *testing.T) { 1015 | if res := IntRange(test.start, test.stop); !res.EqualsOrdered(test.output) { 1016 | t.Errorf("expected %v but got %v", test.output, res) 1017 | } 1018 | }) 1019 | } 1020 | } 1021 | 1022 | func Test_IntsReplicate(t *testing.T) { 1023 | for _, test := range intsReplicateTests { 1024 | t.Run("", func(t *testing.T) { 1025 | if res := IntReplicate(test.count, test.value); !res.Equals(test.output) { 1026 | t.Errorf("expected %v but got %v", test.output, res) 1027 | } 1028 | }) 1029 | } 1030 | } 1031 | 1032 | func Test_IntsTake(t *testing.T) { 1033 | for _, test := range intsTakeTests { 1034 | t.Run("", func(t *testing.T) { 1035 | if res := test.input.Take(test.takeAmount); !res.EqualsOrdered(test.take) { 1036 | t.Errorf("expected %v but got %v", test.take, res) 1037 | } 1038 | }) 1039 | } 1040 | } 1041 | 1042 | func Test_IntsTakewhile(t *testing.T) { 1043 | for _, test := range intsTakeTests { 1044 | t.Run("", func(t *testing.T) { 1045 | if res := test.input.TakeWhile(test.whilePred); !res.EqualsOrdered(test.whileOutput) { 1046 | t.Errorf("expected %v but got %v", test.whileOutput, res) 1047 | } 1048 | }) 1049 | } 1050 | } 1051 | 1052 | func Test_IntsInit(t *testing.T) { 1053 | for _, test := range intsTakeTests { 1054 | t.Run("", func(t *testing.T) { 1055 | if res := test.input.Init(); !res.EqualsOrdered(test.init) { 1056 | t.Errorf("expected %v but got %v", test.init, res) 1057 | } 1058 | }) 1059 | } 1060 | } 1061 | 1062 | func Test_IntsTail(t *testing.T) { 1063 | for _, test := range intsTakeTests { 1064 | t.Run("", func(t *testing.T) { 1065 | if res := test.input.Tail(); !res.EqualsOrdered(test.tail) { 1066 | t.Errorf("expected %v but got %v", test.tail, res) 1067 | } 1068 | }) 1069 | } 1070 | } 1071 | 1072 | func Test_IntsHead(t *testing.T) { 1073 | for _, test := range intsTakeTests { 1074 | t.Run("", func(t *testing.T) { 1075 | if res := test.input.Last(); res != test.last { 1076 | t.Errorf("expected %v but got %v", test.last, res) 1077 | } 1078 | }) 1079 | } 1080 | } 1081 | 1082 | func Test_IntsLast(t *testing.T) { 1083 | for _, test := range intsTakeTests { 1084 | t.Run("", func(t *testing.T) { 1085 | if res := test.input.Head(); res != test.head { 1086 | t.Errorf("expected %v but got %v", test.head, res) 1087 | } 1088 | }) 1089 | } 1090 | } 1091 | 1092 | func Test_IntsReverse(t *testing.T) { 1093 | for _, test := range intsReverseTests { 1094 | t.Run("", func(t *testing.T) { 1095 | if res := test.input.Reverse(); !res.EqualsOrdered(test.output) { 1096 | t.Errorf("expected %v but got %v", test.output, res) 1097 | } 1098 | }) 1099 | } 1100 | } 1101 | 1102 | func Test_IntsUncons(t *testing.T) { 1103 | for _, test := range intsUnconsTests { 1104 | t.Run("", func(t *testing.T) { 1105 | if head, tail := test.input.Uncons(); head != test.head || !tail.EqualsOrdered(test.tail) { 1106 | t.Errorf("expected (%v,%v) but got (%v,%v)", test.head, test.tail, head, tail) 1107 | } 1108 | }) 1109 | } 1110 | } 1111 | 1112 | func Test_IntsMaximum(t *testing.T) { 1113 | for _, test := range intsMinMaxTests { 1114 | t.Run("", func(t *testing.T) { 1115 | if res := test.input.Maximum(); res != test.max { 1116 | t.Errorf("expected %v but got %v", test.max, res) 1117 | } 1118 | }) 1119 | } 1120 | } 1121 | 1122 | func Test_IntsMinimum(t *testing.T) { 1123 | for _, test := range intsMinMaxTests { 1124 | t.Run("", func(t *testing.T) { 1125 | if res := test.input.Minimum(); res != test.min { 1126 | t.Errorf("expected %v but got %v", test.min, res) 1127 | } 1128 | }) 1129 | } 1130 | } 1131 | 1132 | func Test_IntsMap(t *testing.T) { 1133 | for _, test := range intsMapTests { 1134 | t.Run("", func(t *testing.T) { 1135 | if res := test.input.Map(test.mapfunc); !res.EqualsOrdered(test.output) { 1136 | t.Errorf("expected %v but got %v", test.output, res) 1137 | } 1138 | }) 1139 | } 1140 | } 1141 | 1142 | func Test_IntsSort(t *testing.T) { 1143 | for _, test := range intsSortTests { 1144 | t.Run("", func(t *testing.T) { 1145 | if res := test.input.Sort(); !res.EqualsOrdered(test.output) { 1146 | t.Errorf("expected %v but got %v", test.output, res) 1147 | } 1148 | }) 1149 | } 1150 | } 1151 | 1152 | func Test_IntsLength(t *testing.T) { 1153 | for _, test := range intsLengthTests { 1154 | t.Run("", func(t *testing.T) { 1155 | if res := test.input.Length(); res != test.output { 1156 | t.Errorf("expected %v but got %v", test.output, res) 1157 | } 1158 | }) 1159 | } 1160 | } 1161 | 1162 | func Test_IntsNull(t *testing.T) { 1163 | for _, test := range intsBoolTests { 1164 | t.Run("", func(t *testing.T) { 1165 | if res := test.input.Null(); res != test.null { 1166 | t.Errorf("expected %v but got %v", test.null, res) 1167 | } 1168 | }) 1169 | } 1170 | } 1171 | 1172 | func Test_IntsIntersperse(t *testing.T) { 1173 | for _, test := range intsIntersperseTests { 1174 | t.Run("", func(t *testing.T) { 1175 | if res := test.input.Intersperse(test.intersperse); !res.Equals(test.output) { 1176 | t.Errorf("expected %v but got %v", test.output, res) 1177 | } 1178 | }) 1179 | } 1180 | } 1181 | 1182 | func Test_IntsIntercalate(t *testing.T) { 1183 | for _, test := range intsIntercalateTests { 1184 | t.Run("", func(t *testing.T) { 1185 | if res := test.input.Intercalate(test.intercalate); !res.EqualsOrdered(test.output) { 1186 | t.Errorf("expected %v but got %v", test.output, res) 1187 | } 1188 | }) 1189 | } 1190 | } 1191 | 1192 | func Test_IntsModes(t *testing.T) { 1193 | for _, test := range intsModesTests { 1194 | t.Run("", func(t *testing.T) { 1195 | if res := test.input.Modes(); !res.Equals(test.output) { 1196 | t.Errorf("expected %v but got %v", test.output, res) 1197 | } 1198 | }) 1199 | } 1200 | } 1201 | 1202 | func Test_IntsNub(t *testing.T) { 1203 | for _, test := range intsNubTests { 1204 | t.Run("", func(t *testing.T) { 1205 | if res := test.input.Nub(); !res.Equals(test.output) { 1206 | t.Errorf("expected %v but got %v", test.output, res) 1207 | } 1208 | }) 1209 | } 1210 | } 1211 | 1212 | func Test_IntsUnlines(t *testing.T) { 1213 | for _, test := range intsStringTests { 1214 | t.Run("", func(t *testing.T) { 1215 | if res := test.input.Unlines(); res != test.unlines { 1216 | t.Errorf("expected %v but got %v", test.unlines, res) 1217 | } 1218 | }) 1219 | } 1220 | } 1221 | 1222 | func Test_IntsUnwords(t *testing.T) { 1223 | for _, test := range intsStringTests { 1224 | t.Run("", func(t *testing.T) { 1225 | if res := test.input.Unwords(); res != test.unwords { 1226 | t.Errorf("expected %v but got %v", test.unwords, res) 1227 | } 1228 | }) 1229 | } 1230 | } 1231 | 1232 | func Test_IntsDelete(t *testing.T) { 1233 | for _, test := range intsDeleteTests { 1234 | t.Run("", func(t *testing.T) { 1235 | if res := test.input.Delete(test.element); !test.output.EqualsOrdered(res) { 1236 | t.Errorf("expected %v but got %v", test.output, res) 1237 | } 1238 | }) 1239 | } 1240 | } 1241 | 1242 | func Test_IntsMaximumBy(t *testing.T) { 1243 | for _, test := range intsMinMaxByTests { 1244 | t.Run("", func(t *testing.T) { 1245 | if res := test.input.MaximumBy(test.comparator); res != test.max { 1246 | t.Errorf("expected %v but got %v", test.max, res) 1247 | } 1248 | }) 1249 | } 1250 | } 1251 | 1252 | func Test_IntsFoldl(t *testing.T) { 1253 | for _, test := range intsFoldTests { 1254 | t.Run("", func(t *testing.T) { 1255 | if res := test.input.Foldl(test.init, test.foldfunc); res != test.foldl { 1256 | t.Errorf("expected %v but got %v", test.foldl, res) 1257 | } 1258 | }) 1259 | } 1260 | } 1261 | 1262 | func Test_IntsFoldl1(t *testing.T) { 1263 | for _, test := range intsFoldTests { 1264 | t.Run("", func(t *testing.T) { 1265 | if res := test.input.Foldl1(test.foldfunc); res != test.foldl1 { 1266 | t.Errorf("expected %v but got %v", test.foldl1, res) 1267 | } 1268 | }) 1269 | } 1270 | } 1271 | 1272 | func Test_IntsFoldr(t *testing.T) { 1273 | for _, test := range intsFoldTests { 1274 | t.Run("", func(t *testing.T) { 1275 | if res := test.input.Foldr(test.init, test.foldfunc); res != test.foldr { 1276 | t.Errorf("expected #{test.foldr} but got #{res}") 1277 | } 1278 | }) 1279 | } 1280 | } 1281 | 1282 | func Test_IntsFoldr1(t *testing.T) { 1283 | for _, test := range intsFoldTests { 1284 | t.Run("", func(t *testing.T) { 1285 | if res := test.input.Foldr1(test.foldfunc); res != test.foldr1 { 1286 | t.Errorf("expected %v but got %v", test.foldr1, res) 1287 | } 1288 | }) 1289 | } 1290 | } 1291 | 1292 | func Test_IntsElem(t *testing.T) { 1293 | for _, test := range intsElemTests { 1294 | t.Run("", func(t *testing.T) { 1295 | if res := test.input.Elem(test.needle); res != test.output { 1296 | t.Errorf("expected %v but got %v", test.output, res) 1297 | } 1298 | }) 1299 | } 1300 | } 1301 | 1302 | func Test_IntsDrop(t *testing.T) { 1303 | for _, test := range intsDropTests { 1304 | t.Run("", func(t *testing.T) { 1305 | if res := test.input.Drop(test.drop); !test.output.Equals(res) { 1306 | t.Errorf("expected %v but got %v", test.output, res) 1307 | } 1308 | }) 1309 | } 1310 | } 1311 | 1312 | func Test_IntsSpan(t *testing.T) { 1313 | for _, test := range intsSpanTests { 1314 | t.Run("", func(t *testing.T) { 1315 | before, after := test.input.Span(test.spanfunc) 1316 | if !test.before.Equals(before) || !test.after.Equals(after) { 1317 | t.Errorf("expected (%v, %v) but got (%v, %v)", test.before, test.after, before, after) 1318 | } 1319 | }) 1320 | } 1321 | } 1322 | 1323 | func Test_IntsDropWhile(t *testing.T) { 1324 | for _, test := range intsDropWhileTests { 1325 | t.Run("", func(t *testing.T) { 1326 | if res := test.input.DropWhile(test.dropfunc); !test.output.Equals(res) { 1327 | t.Errorf("expected %v but got %v", test.output, res) 1328 | } 1329 | }) 1330 | } 1331 | } 1332 | 1333 | func Test_IntsBreak(t *testing.T) { 1334 | for _, test := range intsBreakTests { 1335 | t.Run("", func(t *testing.T) { 1336 | before, after := test.input.Break(test.breakfunc) 1337 | if !test.before.Equals(before) || !test.after.Equals(after) { 1338 | t.Errorf("expected %v, %v but got %v, %v", test.before, test.after, before, after) 1339 | } 1340 | }) 1341 | } 1342 | } 1343 | 1344 | func Test_IntsInits(t *testing.T) { 1345 | for _, test := range intsInitsTests { 1346 | t.Run("", func(t *testing.T) { 1347 | res := test.input.Inits() 1348 | for i, v := range test.output { 1349 | if !v.EqualsOrdered(res[i]) { 1350 | t.Errorf("expected %v but got %v", v, res[i]) 1351 | } 1352 | } 1353 | }) 1354 | } 1355 | } 1356 | 1357 | func Test_IntsTails(t *testing.T) { 1358 | for _, test := range intsTailsTests { 1359 | t.Run("", func(t *testing.T) { 1360 | res := test.input.Tails() 1361 | for i, v := range test.output { 1362 | if !v.EqualsOrdered(res[i]) { 1363 | t.Errorf("expected %v but got %v", v, res[i]) 1364 | } 1365 | } 1366 | }) 1367 | } 1368 | } 1369 | 1370 | func Test_IntsSplitAt(t *testing.T) { 1371 | for _, test := range intsSplitAtTests { 1372 | t.Run("", func(t *testing.T) { 1373 | if before, after := test.input.SplitAt(test.i); !test.before.Equals(before) || !test.after.Equals(after) { 1374 | t.Errorf("expected %v, %v but got %v, %v", test.before, test.after, before, after) 1375 | } 1376 | }) 1377 | } 1378 | } 1379 | 1380 | func Test_IntsGroup(t *testing.T) { 1381 | for _, test := range intsGroupTests { 1382 | t.Run("", func(t *testing.T) { 1383 | res := test.input.Group() 1384 | for i, v := range test.output { 1385 | if !v.EqualsOrdered(res[i]) { 1386 | t.Errorf("expected %v but got %v", v, res[i]) 1387 | } 1388 | } 1389 | }) 1390 | } 1391 | } 1392 | 1393 | func Test_IntsIsPrefixOf(t *testing.T) { 1394 | for _, test := range intsIsPrefixTests { 1395 | t.Run("", func(t *testing.T) { 1396 | res := test.input.IsPrefixOf(test.param1) 1397 | if res != test.output { 1398 | t.Errorf("expected %v but got %v", test.output, res) 1399 | } 1400 | }) 1401 | } 1402 | } 1403 | 1404 | func Test_IntsScanl(t *testing.T) { 1405 | for _, test := range intsScanTests { 1406 | t.Run("", func(t *testing.T) { 1407 | if res := test.input.Scanl(test.init, test.scanfunc); !test.scanl.Equals(res) { 1408 | t.Errorf("expected #{test.scanl} but got #{res}") 1409 | } 1410 | }) 1411 | } 1412 | } 1413 | -------------------------------------------------------------------------------- /types/Person.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | //go:generate hasgo -T=person -S=persons 4 | type persons []person 5 | 6 | type person struct { 7 | firstname string 8 | lastname string 9 | age int 10 | } 11 | 12 | // String returns the firstname and lastname of the person. 13 | func (p person) String() string { 14 | return p.firstname + " " + p.lastname 15 | } 16 | 17 | // EqualsOrdered verifies that both slices have the same elements in the same position. 18 | func (is persons) EqualsOrdered(other persons) bool { 19 | if len(is) != len(other) { 20 | return false 21 | } 22 | for i := range is { 23 | if is[i] != other[i] { 24 | return false 25 | } 26 | } 27 | return true 28 | } 29 | 30 | // Equals verifies that both slices have the same elements regardless of position. 31 | func (is persons) Equals(other persons) bool { 32 | if len(is) != len(other) { 33 | return false 34 | } 35 | contains := make(map[person]struct{}, 0) 36 | for _, i := range is { 37 | contains[i] = struct{}{} 38 | } 39 | for _, i := range other { 40 | if _, ok := contains[i]; !ok { 41 | return false 42 | } 43 | } 44 | return true 45 | } 46 | -------------------------------------------------------------------------------- /types/Persons_test.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | var ( 8 | dylan = person{"Dylan", "Meeus", 26} 9 | ana = person{"Ana", "Esparza", 30} 10 | sean = person{"Sean", "West", 25} 11 | tom = person{"Tom", "Devrolijke", 26} 12 | chris = person{"Chris", "Evans", 27} 13 | 14 | structFilterTests = []struct { 15 | input persons 16 | filter func(person) bool 17 | output persons 18 | }{ 19 | { 20 | nil, 21 | func(p person) bool { return p.age == 26 }, 22 | persons{}, 23 | }, 24 | { 25 | persons{}, 26 | func(p person) bool { return p.age == 26 }, 27 | persons{}, 28 | }, 29 | { 30 | persons{dylan, ana, sean, tom}, 31 | func(p person) bool { return p.age == 26 }, 32 | persons{tom, dylan}, 33 | }, 34 | } 35 | 36 | structPredicateTests = []struct { 37 | input persons 38 | predicate func(person) bool 39 | any bool 40 | all bool 41 | }{ 42 | { 43 | nil, 44 | func(p person) bool { return p.age == 26 }, 45 | false, 46 | true, 47 | }, 48 | { 49 | persons{}, 50 | func(p person) bool { return p.age == 26 }, 51 | false, 52 | true, 53 | }, 54 | { 55 | persons{dylan, chris}, 56 | func(p person) bool { return p.age == 26 }, 57 | true, 58 | false, 59 | }, 60 | { 61 | persons{dylan, tom}, 62 | func(p person) bool { return p.age == 26 }, 63 | true, 64 | true, 65 | }, 66 | { 67 | persons{dylan, tom}, 68 | func(p person) bool { return p.age == 30 }, 69 | false, 70 | false, 71 | }, 72 | } 73 | 74 | structTakeTests = []struct { 75 | input persons 76 | takeAmount uint64 77 | take persons 78 | init persons 79 | tail persons 80 | head person 81 | last person 82 | whilePred func(person) bool 83 | whileOutput persons 84 | }{ 85 | { 86 | nil, 87 | 2, 88 | persons{}, 89 | persons{}, 90 | persons{}, 91 | person{}, 92 | person{}, 93 | func(p person) bool { return p.age < 30 }, 94 | persons{}, 95 | }, 96 | { 97 | persons{}, 98 | 2, 99 | persons{}, 100 | persons{}, 101 | persons{}, 102 | person{}, 103 | person{}, 104 | func(p person) bool { return p.age < 30 }, 105 | persons{}, 106 | }, 107 | { 108 | persons{dylan, ana, sean, tom}, 109 | 2, 110 | persons{dylan, ana}, 111 | persons{dylan, ana, sean}, 112 | persons{ana, sean, tom}, 113 | dylan, 114 | tom, 115 | func(p person) bool { return p.age < 30 }, 116 | persons{dylan}, 117 | }, 118 | } 119 | 120 | structReverseTests = []struct { 121 | input persons 122 | output persons 123 | }{ 124 | { 125 | nil, 126 | persons{}, 127 | }, 128 | { 129 | persons{}, 130 | persons{}, 131 | }, 132 | { 133 | persons{dylan, ana, sean, tom}, 134 | persons{tom, sean, ana, dylan}, 135 | }, 136 | } 137 | 138 | structUnconsTests = []struct { 139 | input persons 140 | head person 141 | tail persons 142 | }{ 143 | { 144 | nil, 145 | person{}, 146 | persons{}, 147 | }, 148 | { 149 | persons{}, 150 | person{}, 151 | persons{}, 152 | }, 153 | { 154 | persons{dylan, ana, sean, tom}, 155 | dylan, 156 | persons{ana, sean, tom}, 157 | }, 158 | } 159 | 160 | structMapTests = []struct { 161 | input persons 162 | mapfunc func(person) person 163 | output persons 164 | }{ 165 | { 166 | nil, 167 | func(p person) person { return dylan }, 168 | persons{}, 169 | }, 170 | { 171 | persons{}, 172 | func(p person) person { return dylan }, 173 | persons{}, 174 | }, 175 | { 176 | persons{dylan, ana, sean}, 177 | func(p person) person { return dylan }, 178 | persons{dylan, dylan, dylan}, 179 | }, 180 | } 181 | 182 | structLengthTests = []struct { 183 | input persons 184 | output int 185 | }{ 186 | { 187 | persons{dylan, ana, sean}, 188 | 3, 189 | }, 190 | { 191 | persons{}, 192 | 0, 193 | }, 194 | { 195 | nil, 196 | 0, 197 | }, 198 | } 199 | 200 | structBoolTests = []struct { 201 | input persons 202 | null bool 203 | }{ 204 | { 205 | persons{dylan}, 206 | false, 207 | }, 208 | { 209 | persons{}, 210 | true, 211 | }, 212 | { 213 | nil, 214 | true, 215 | }, 216 | } 217 | 218 | structIntersperseTests = []struct { 219 | input persons 220 | intersperse person 221 | output persons 222 | }{ 223 | { 224 | nil, 225 | dylan, 226 | persons{}, 227 | }, 228 | { 229 | persons{}, 230 | dylan, 231 | persons{}, 232 | }, 233 | { 234 | persons{ana, dylan, sean}, 235 | chris, 236 | persons{ana, chris, dylan, chris, sean}, 237 | }, 238 | { 239 | persons{ana}, 240 | dylan, 241 | persons{ana}, 242 | }, 243 | } 244 | 245 | structIntercalateTests = []struct { 246 | input persons 247 | intercalate [][]person 248 | output persons 249 | }{ 250 | { 251 | nil, 252 | [][]person{ 253 | {ana, sean}, 254 | {tom}, 255 | }, 256 | persons{ana, sean, tom}, 257 | }, 258 | { 259 | persons{}, 260 | [][]person{ 261 | {ana, sean}, 262 | {tom}, 263 | }, 264 | persons{ana, sean, tom}, 265 | }, 266 | { 267 | persons{dylan}, 268 | [][]person{ 269 | {ana, sean}, 270 | {tom}, 271 | }, 272 | persons{ana, sean, dylan, tom}, 273 | }, 274 | { 275 | persons{chris}, 276 | [][]person{ 277 | {ana, dylan}, 278 | {sean}, 279 | {tom}, 280 | }, 281 | persons{ana, dylan, chris, sean, chris, tom}, 282 | }, 283 | } 284 | 285 | structModesTests = []struct { 286 | input persons 287 | output persons 288 | }{ 289 | { 290 | nil, 291 | persons{}, 292 | }, 293 | { 294 | persons{}, 295 | persons{}, 296 | }, 297 | { 298 | persons{ana, dylan}, 299 | persons{ana, dylan}, 300 | }, 301 | { 302 | persons{ana, ana, dylan, dylan}, 303 | persons{ana, dylan}, 304 | }, 305 | { 306 | persons{ana, dylan, dylan}, 307 | persons{dylan}, 308 | }, 309 | } 310 | 311 | structNubTests = []struct { 312 | input persons 313 | output persons 314 | }{ 315 | { 316 | nil, 317 | persons{}, 318 | }, 319 | { 320 | persons{}, 321 | persons{}, 322 | }, 323 | { 324 | persons{ana, dylan}, 325 | persons{ana, dylan}, 326 | }, 327 | { 328 | persons{ana, dylan, chris, dylan, ana}, 329 | persons{ana, dylan, chris}, 330 | }, 331 | { 332 | persons{ana, ana, ana}, 333 | persons{ana}, 334 | }, 335 | } 336 | 337 | structStringTests = []struct { 338 | input persons 339 | unlines string 340 | unwords string 341 | }{ 342 | { 343 | nil, 344 | "", 345 | "", 346 | }, 347 | { 348 | persons{}, 349 | "", 350 | "", 351 | }, 352 | { 353 | persons{dylan, ana}, 354 | "Dylan Meeus\nAna Esparza", 355 | "Dylan Meeus Ana Esparza", 356 | }, 357 | } 358 | 359 | structDeleteTests = []struct { 360 | input persons 361 | element person 362 | output persons 363 | }{ 364 | { 365 | nil, 366 | ana, 367 | persons{}, 368 | }, 369 | { 370 | persons{}, 371 | dylan, 372 | persons{}, 373 | }, 374 | { 375 | persons{dylan, ana, ana, dylan}, 376 | ana, 377 | persons{dylan, ana, dylan}, 378 | }, 379 | } 380 | 381 | structMinMaxByTests = []struct { 382 | input persons 383 | comparator func(p1, p2 person) person 384 | max person 385 | }{ 386 | { 387 | nil, 388 | func(p1, p2 person) person { return p1 }, 389 | person{}, 390 | }, 391 | { 392 | persons{}, 393 | func(p1, p2 person) person { return p1 }, 394 | person{}, 395 | }, 396 | { 397 | persons{dylan, ana, sean}, 398 | func(p1, p2 person) person { 399 | if p1.age > p2.age { 400 | return p1 401 | } 402 | return p2 403 | }, 404 | ana, 405 | }, 406 | } 407 | 408 | structFoldTests = []struct { 409 | input persons 410 | init person 411 | foldfunc func(p1, p2 person) person 412 | foldl person 413 | foldl1 person 414 | foldr person 415 | foldr1 person 416 | }{ 417 | { 418 | nil, 419 | person{}, 420 | func(p1, p2 person) person { return p1 }, 421 | person{}, 422 | person{}, 423 | person{}, 424 | person{}, 425 | }, 426 | { 427 | persons{}, 428 | person{}, 429 | func(p1, p2 person) person { return p1 }, 430 | person{}, 431 | person{}, 432 | person{}, 433 | person{}, 434 | }, 435 | { 436 | persons{dylan, ana, sean}, 437 | person{}, 438 | func(p1, p2 person) person { 439 | if p1.age > p2.age { 440 | return p1 441 | } 442 | return p2 443 | }, 444 | ana, 445 | ana, 446 | ana, 447 | ana, 448 | }, 449 | } 450 | 451 | structElemTests = []struct { 452 | input persons 453 | needle person 454 | output bool 455 | }{ 456 | { 457 | nil, 458 | ana, 459 | false, 460 | }, 461 | { 462 | persons{}, 463 | ana, 464 | false, 465 | }, 466 | { 467 | persons{dylan, ana, sean}, 468 | ana, 469 | true, 470 | }, 471 | { 472 | persons{dylan, sean}, 473 | ana, 474 | false, 475 | }, 476 | } 477 | 478 | structDropTests = []struct { 479 | input persons 480 | drop int 481 | output persons 482 | }{ 483 | { 484 | nil, 485 | 0, 486 | persons{}, 487 | }, 488 | { 489 | persons{}, 490 | 0, 491 | persons{}, 492 | }, 493 | { 494 | persons{dylan, ana, sean, chris}, 495 | 5, 496 | persons{}, 497 | }, 498 | { 499 | persons{dylan, ana, sean, chris}, 500 | 1, 501 | persons{ana, sean, chris}, 502 | }, 503 | { 504 | persons{dylan, ana, sean, chris}, 505 | 3, 506 | persons{chris}, 507 | }, 508 | } 509 | 510 | structSpanTests = []struct { 511 | input persons 512 | spanfunc func(person) bool 513 | before persons 514 | after persons 515 | }{ 516 | { 517 | nil, 518 | func(p person) bool { return p.age < 27 }, 519 | persons{}, 520 | persons{}, 521 | }, 522 | { 523 | persons{}, 524 | func(p person) bool { return p.age < 27 }, 525 | persons{}, 526 | persons{}, 527 | }, 528 | { 529 | persons{dylan, ana, sean, tom, chris}, 530 | nil, 531 | persons{}, 532 | persons{dylan, ana, sean, tom, chris}, 533 | }, 534 | { 535 | persons{dylan, ana, sean, tom, chris}, 536 | func(p person) bool { return p.age < 100 }, 537 | persons{dylan, ana, sean, tom, chris}, 538 | persons{}, 539 | }, 540 | { 541 | persons{dylan, ana, sean, tom, chris}, 542 | func(p person) bool { return p.age > 100 }, 543 | persons{}, 544 | persons{dylan, ana, sean, tom, chris}, 545 | }, 546 | { 547 | persons{dylan, ana, sean, tom, chris}, 548 | func(p person) bool { return p.age < 27 }, 549 | persons{dylan}, 550 | persons{ana, sean, tom, chris}, 551 | }, 552 | } 553 | 554 | structDropWhileTests = []struct { 555 | input persons 556 | dropfunc func(person) bool 557 | output persons 558 | }{ 559 | { 560 | nil, 561 | func(p person) bool { return p.age < 27 }, 562 | persons{}, 563 | }, 564 | { 565 | persons{}, 566 | func(p person) bool { return p.age < 27 }, 567 | persons{}, 568 | }, 569 | { 570 | persons{dylan, ana, sean, tom, chris}, 571 | nil, 572 | persons{dylan, ana, sean, tom, chris}, 573 | }, 574 | { 575 | persons{dylan, ana, sean, tom, chris}, 576 | func(p person) bool { return p.age < 50 }, 577 | persons{}, 578 | }, 579 | { 580 | persons{dylan, ana, sean, tom, chris}, 581 | func(p person) bool { return p.age < 30 }, 582 | persons{ana, sean, tom, chris}, 583 | }, 584 | } 585 | 586 | structBreakTests = []struct { 587 | input persons 588 | breakfunc func(person) bool 589 | before persons 590 | after persons 591 | }{ 592 | { 593 | nil, 594 | func(p person) bool { return p.age < 27 }, 595 | persons{}, 596 | persons{}, 597 | }, 598 | { 599 | persons{}, 600 | func(p person) bool { return p.age < 27 }, 601 | persons{}, 602 | persons{}, 603 | }, 604 | { 605 | persons{sean, dylan, tom, chris, ana}, 606 | nil, 607 | persons{}, 608 | persons{sean, dylan, tom, chris, ana}, 609 | }, 610 | { 611 | persons{sean, dylan, tom, chris, ana}, 612 | func(p person) bool { return p.age < 100 }, 613 | persons{}, 614 | persons{sean, dylan, tom, chris, ana}, 615 | }, 616 | { 617 | persons{sean, dylan, tom, chris, ana}, 618 | func(p person) bool { return p.age > 100 }, 619 | persons{sean, dylan, tom, chris, ana}, 620 | persons{}, 621 | }, 622 | { 623 | persons{sean, dylan, tom, chris, ana}, 624 | func(p person) bool { return p.age > 26 }, 625 | persons{sean, dylan, tom}, 626 | persons{chris, ana}, 627 | }, 628 | } 629 | 630 | structInitsTests = []struct { 631 | input persons 632 | output []persons 633 | }{ 634 | { 635 | nil, 636 | []persons{}, 637 | }, 638 | { 639 | persons{}, 640 | []persons{}, 641 | }, 642 | { 643 | persons{sean, dylan, tom, chris, ana}, 644 | []persons{ 645 | {}, 646 | {sean}, 647 | {sean, dylan}, 648 | {sean, dylan, tom}, 649 | {sean, dylan, tom, chris}, 650 | {sean, dylan, tom, chris, ana}, 651 | }, 652 | }, 653 | } 654 | 655 | structTailsTests = []struct { 656 | input persons 657 | output []persons 658 | }{ 659 | { 660 | nil, 661 | []persons{}, 662 | }, 663 | { 664 | persons{}, 665 | []persons{}, 666 | }, 667 | { 668 | persons{sean, dylan, tom, chris, ana}, 669 | []persons{ 670 | {sean, dylan, tom, chris, ana}, 671 | {dylan, tom, chris, ana}, 672 | {tom, chris, ana}, 673 | {chris, ana}, 674 | {ana}, 675 | {}, 676 | }, 677 | }, 678 | } 679 | 680 | structSplitAtTests = []struct { 681 | input persons 682 | i int 683 | before persons 684 | after persons 685 | }{ 686 | { 687 | nil, 688 | 5, 689 | persons{}, 690 | persons{}, 691 | }, 692 | { 693 | persons{}, 694 | 5, 695 | persons{}, 696 | persons{}, 697 | }, 698 | { 699 | persons{dylan, ana, sean, tom, chris}, 700 | 0, 701 | persons{}, 702 | persons{dylan, ana, sean, tom, chris}, 703 | }, 704 | { 705 | persons{dylan, ana, sean, tom, chris}, 706 | -1, 707 | persons{}, 708 | persons{dylan, ana, sean, tom, chris}, 709 | }, 710 | { 711 | persons{dylan, ana, sean, tom, chris}, 712 | 10, 713 | persons{dylan, ana, sean, tom, chris}, 714 | persons{}, 715 | }, 716 | { 717 | persons{dylan, ana, sean, tom, chris}, 718 | 5, 719 | persons{dylan, ana, sean, tom, chris}, 720 | persons{}, 721 | }, 722 | { 723 | persons{dylan, ana, sean, tom, chris}, 724 | 3, 725 | persons{dylan, ana, sean}, 726 | persons{tom, chris}, 727 | }, 728 | } 729 | 730 | structGroupTests = []struct { 731 | input persons 732 | output []persons 733 | }{ 734 | { 735 | nil, 736 | []persons{}, 737 | }, 738 | { 739 | persons{}, 740 | []persons{}, 741 | }, 742 | { 743 | persons{dylan, ana, sean}, 744 | []persons{{dylan}, {ana}, {sean}}, 745 | }, 746 | { 747 | persons{dylan, dylan, ana, ana, chris, sean, sean, sean}, 748 | []persons{{dylan, dylan}, {ana, ana}, {chris}, {sean, sean, sean}}, 749 | }, 750 | } 751 | 752 | structScanTests = []struct { 753 | input persons 754 | init person 755 | scanfunc func(person, person) person 756 | scanl persons 757 | }{ 758 | { 759 | nil, 760 | person{}, 761 | func(p1, p2 person) person { return p1 }, 762 | persons{}, 763 | }, 764 | { 765 | persons{}, 766 | person{}, 767 | func(p1, p2 person) person { return p1 }, 768 | persons{}, 769 | }, 770 | { 771 | persons{dylan, ana, sean}, 772 | chris, 773 | func(p1, p2 person) person { return p1 }, 774 | persons{chris, dylan, ana, sean}, 775 | }, 776 | } 777 | 778 | structIsPrefixOfTests = []struct { 779 | input persons 780 | param1 persons 781 | output bool 782 | }{ 783 | { 784 | persons{}, 785 | persons{}, 786 | true, 787 | }, 788 | { 789 | nil, 790 | persons{}, 791 | true, 792 | }, 793 | { 794 | persons{dylan, ana, sean}, 795 | persons{dylan}, 796 | false, 797 | }, 798 | { 799 | persons{}, 800 | persons{dylan}, 801 | true, 802 | }, 803 | { 804 | persons{dylan}, 805 | persons{dylan, ana}, 806 | true, 807 | }, 808 | { 809 | persons{dylan}, 810 | persons{dylan}, 811 | true, 812 | }, 813 | { 814 | persons{dylan}, 815 | persons{ana}, 816 | false, 817 | }, 818 | } 819 | ) 820 | 821 | func Test_StructFilter(t *testing.T) { 822 | for _, test := range structFilterTests { 823 | t.Run("", func(t *testing.T) { 824 | if res := test.input.Filter(test.filter); !res.Equals(test.output) { 825 | t.Errorf("expected %v but got %v", test.output, res) 826 | } 827 | }) 828 | } 829 | } 830 | 831 | func Test_StructAny(t *testing.T) { 832 | for _, test := range structPredicateTests { 833 | t.Run("", func(t *testing.T) { 834 | if res := test.input.Any(test.predicate); res != test.any { 835 | t.Errorf("expected %v but got %v", test.any, res) 836 | } 837 | }) 838 | } 839 | } 840 | 841 | func Test_StructAll(t *testing.T) { 842 | for _, test := range structPredicateTests { 843 | t.Run("", func(t *testing.T) { 844 | if res := test.input.All(test.predicate); res != test.all { 845 | t.Errorf("expected %v but got %v", test.all, res) 846 | } 847 | }) 848 | } 849 | } 850 | 851 | func Test_StructTake(t *testing.T) { 852 | for _, test := range structTakeTests { 853 | t.Run("", func(t *testing.T) { 854 | if res := test.input.Take(test.takeAmount); !res.EqualsOrdered(test.take) { 855 | t.Errorf("expected %v but got %v", test.take, res) 856 | } 857 | }) 858 | } 859 | } 860 | 861 | func Test_StructTakeWhile(t *testing.T) { 862 | for _, test := range structTakeTests { 863 | t.Run("", func(t *testing.T) { 864 | if res := test.input.TakeWhile(test.whilePred); !res.EqualsOrdered(test.whileOutput) { 865 | t.Errorf("expected %v but got %v", test.whileOutput, res) 866 | } 867 | }) 868 | } 869 | } 870 | 871 | func Test_StructInit(t *testing.T) { 872 | for _, test := range structTakeTests { 873 | t.Run("", func(t *testing.T) { 874 | if res := test.input.Init(); !res.EqualsOrdered(test.init) { 875 | t.Errorf("expected %v but got %v", test.init, res) 876 | } 877 | }) 878 | } 879 | } 880 | 881 | func Test_StructTail(t *testing.T) { 882 | for _, test := range structTakeTests { 883 | t.Run("", func(t *testing.T) { 884 | if res := test.input.Tail(); !res.EqualsOrdered(test.tail) { 885 | t.Errorf("expected %v but got %v", test.tail, res) 886 | } 887 | }) 888 | } 889 | } 890 | 891 | func Test_StructHead(t *testing.T) { 892 | for _, test := range structTakeTests { 893 | t.Run("", func(t *testing.T) { 894 | if res := test.input.Head(); res != test.head { 895 | t.Errorf("expected %v but got %v", test.head, res) 896 | } 897 | }) 898 | } 899 | } 900 | 901 | func Test_StructLast(t *testing.T) { 902 | for _, test := range structTakeTests { 903 | t.Run("", func(t *testing.T) { 904 | if res := test.input.Last(); res != test.last { 905 | t.Errorf("expected %v but got %v", test.last, res) 906 | } 907 | }) 908 | } 909 | } 910 | 911 | func Test_StructReverse(t *testing.T) { 912 | for _, test := range structReverseTests { 913 | t.Run("", func(t *testing.T) { 914 | if res := test.input.Reverse(); !res.EqualsOrdered(test.output) { 915 | t.Errorf("expected %v but got %v", test.output, res) 916 | } 917 | }) 918 | } 919 | } 920 | 921 | func Test_StructUncons(t *testing.T) { 922 | for _, test := range structUnconsTests { 923 | t.Run("", func(t *testing.T) { 924 | if head, tail := test.input.Uncons(); head != test.head || !tail.EqualsOrdered(test.tail) { 925 | t.Errorf("expected (%v,%v) but got (%v,%v)", test.head, test.tail, head, tail) 926 | } 927 | }) 928 | } 929 | } 930 | 931 | func Test_StructLength(t *testing.T) { 932 | for _, test := range structLengthTests { 933 | t.Run("", func(t *testing.T) { 934 | if res := test.input.Length(); res != test.output { 935 | t.Errorf("expected %v but got %v", test.output, res) 936 | } 937 | }) 938 | } 939 | } 940 | func Test_StructMap(t *testing.T) { 941 | for _, test := range structMapTests { 942 | t.Run("", func(t *testing.T) { 943 | if res := test.input.Map(test.mapfunc); !res.EqualsOrdered(test.output) { 944 | t.Errorf("expected %v but got %v", test.output, res) 945 | } 946 | }) 947 | } 948 | } 949 | 950 | func Test_StructNull(t *testing.T) { 951 | for _, test := range structBoolTests { 952 | t.Run("", func(t *testing.T) { 953 | if res := test.input.Null(); res != test.null { 954 | t.Errorf("expected %v but got %v", test.null, res) 955 | } 956 | }) 957 | } 958 | } 959 | 960 | func Test_StructIntersperse(t *testing.T) { 961 | for _, test := range structIntersperseTests { 962 | t.Run("", func(t *testing.T) { 963 | if res := test.input.Intersperse(test.intersperse); !res.Equals(test.output) { 964 | t.Errorf("expected %v but got %v", test.output, res) 965 | } 966 | }) 967 | } 968 | } 969 | 970 | func Test_StructIntercalate(t *testing.T) { 971 | for _, test := range structIntercalateTests { 972 | t.Run("", func(t *testing.T) { 973 | if res := test.input.Intercalate(test.intercalate); !res.EqualsOrdered(test.output) { 974 | t.Errorf("expected %v but got %v", test.output, res) 975 | } 976 | }) 977 | } 978 | } 979 | 980 | func Test_StructModes(t *testing.T) { 981 | for _, test := range structModesTests { 982 | t.Run("", func(t *testing.T) { 983 | if res := test.input.Modes(); !res.Equals(test.output) { 984 | t.Errorf("expected %v but got %v", test.output, res) 985 | } 986 | }) 987 | } 988 | } 989 | 990 | func Test_StructNub(t *testing.T) { 991 | for _, test := range structNubTests { 992 | t.Run("", func(t *testing.T) { 993 | if res := test.input.Nub(); !res.Equals(test.output) { 994 | t.Errorf("expected %v but got %v", test.output, res) 995 | } 996 | }) 997 | } 998 | } 999 | 1000 | func Test_StructUnlines(t *testing.T) { 1001 | for _, test := range structStringTests { 1002 | t.Run("", func(t *testing.T) { 1003 | if res := test.input.Unlines(); res != test.unlines { 1004 | t.Errorf("expected %v but got %v", test.unlines, res) 1005 | } 1006 | }) 1007 | } 1008 | } 1009 | 1010 | func Test_StructUnwords(t *testing.T) { 1011 | for _, test := range structStringTests { 1012 | t.Run("", func(t *testing.T) { 1013 | if res := test.input.Unwords(); res != test.unwords { 1014 | t.Errorf("expected %v but got %v", test.unwords, res) 1015 | } 1016 | }) 1017 | } 1018 | } 1019 | 1020 | func Test_StructDelete(t *testing.T) { 1021 | for _, test := range structDeleteTests { 1022 | t.Run("", func(t *testing.T) { 1023 | if res := test.input.Delete(test.element); !res.EqualsOrdered(test.output) { 1024 | t.Errorf("expected %v but got %v", test.output, res) 1025 | } 1026 | }) 1027 | } 1028 | } 1029 | 1030 | func Test_structMaximumBy(t *testing.T) { 1031 | for _, test := range structMinMaxByTests { 1032 | t.Run("", func(t *testing.T) { 1033 | if res := test.input.MaximumBy(test.comparator); res != test.max { 1034 | t.Errorf("expected %v but got %v", test.max, res) 1035 | } 1036 | }) 1037 | } 1038 | } 1039 | 1040 | func Test_structFoldl(t *testing.T) { 1041 | for _, test := range structFoldTests { 1042 | t.Run("", func(t *testing.T) { 1043 | if res := test.input.Foldl(test.init, test.foldfunc); res != test.foldl { 1044 | t.Errorf("expected %v but got %v", test.foldl, res) 1045 | } 1046 | }) 1047 | } 1048 | } 1049 | 1050 | func Test_structFoldl1(t *testing.T) { 1051 | for _, test := range structFoldTests { 1052 | t.Run("", func(t *testing.T) { 1053 | if res := test.input.Foldl1(test.foldfunc); res != test.foldl1 { 1054 | t.Errorf("expected %v but got %v", test.foldl1, res) 1055 | } 1056 | }) 1057 | } 1058 | } 1059 | 1060 | func Test_structFoldr(t *testing.T) { 1061 | for _, test := range structFoldTests { 1062 | t.Run("", func(t *testing.T) { 1063 | if res := test.input.Foldr(test.init, test.foldfunc); res != test.foldr { 1064 | t.Errorf("expected %v but got %v", test.foldr, res) 1065 | } 1066 | }) 1067 | } 1068 | } 1069 | 1070 | func Test_structFoldr1(t *testing.T) { 1071 | for _, test := range structFoldTests { 1072 | t.Run("", func(t *testing.T) { 1073 | if res := test.input.Foldr1(test.foldfunc); res != test.foldr1 { 1074 | t.Errorf("expected %v but got %v", test.foldr1, res) 1075 | } 1076 | }) 1077 | } 1078 | } 1079 | 1080 | func Test_structElem(t *testing.T) { 1081 | for _, test := range structElemTests { 1082 | t.Run("", func(t *testing.T) { 1083 | if res := test.input.Elem(test.needle); res != test.output { 1084 | t.Errorf("expected %v but got %v", test.output, res) 1085 | } 1086 | }) 1087 | } 1088 | } 1089 | 1090 | func Test_structDrop(t *testing.T) { 1091 | for _, test := range structDropTests { 1092 | t.Run("", func(t *testing.T) { 1093 | if res := test.input.Drop(test.drop); !test.output.Equals(res) { 1094 | t.Errorf("expected %v but got %v", test.output, res) 1095 | } 1096 | }) 1097 | } 1098 | } 1099 | 1100 | func Test_structSpan(t *testing.T) { 1101 | for _, test := range structSpanTests { 1102 | t.Run("", func(t *testing.T) { 1103 | before, after := test.input.Span(test.spanfunc) 1104 | if !test.before.Equals(before) || !test.after.Equals(after) { 1105 | t.Errorf("expected (%v, %v) but got (%v, %v)", test.before, test.after, before, after) 1106 | } 1107 | }) 1108 | } 1109 | } 1110 | 1111 | func Test_structDropWhile(t *testing.T) { 1112 | for _, test := range structDropWhileTests { 1113 | t.Run("", func(t *testing.T) { 1114 | if res := test.input.DropWhile(test.dropfunc); !test.output.Equals(res) { 1115 | t.Errorf("expected %v but got %v", test.output, res) 1116 | } 1117 | }) 1118 | } 1119 | } 1120 | 1121 | func Test_structBreak(t *testing.T) { 1122 | for _, test := range structBreakTests { 1123 | t.Run("", func(t *testing.T) { 1124 | before, after := test.input.Break(test.breakfunc) 1125 | if !test.before.Equals(before) || !test.after.Equals(after) { 1126 | t.Errorf("expected %v, %v but got %v, %v", test.before, test.after, before, after) 1127 | } 1128 | }) 1129 | } 1130 | } 1131 | 1132 | func Test_structInits(t *testing.T) { 1133 | for _, test := range structInitsTests { 1134 | t.Run("", func(t *testing.T) { 1135 | res := test.input.Inits() 1136 | for i, v := range test.output { 1137 | if !v.EqualsOrdered(res[i]) { 1138 | t.Errorf("expected %v but got %v", v, res[i]) 1139 | } 1140 | } 1141 | }) 1142 | } 1143 | } 1144 | 1145 | func Test_structTails(t *testing.T) { 1146 | for _, test := range structTailsTests { 1147 | t.Run("", func(t *testing.T) { 1148 | res := test.input.Tails() 1149 | for i, v := range test.output { 1150 | if !v.EqualsOrdered(res[i]) { 1151 | t.Errorf("expected %v but got %v", v, res[i]) 1152 | } 1153 | } 1154 | }) 1155 | } 1156 | } 1157 | 1158 | func Test_structSplitAt(t *testing.T) { 1159 | for _, test := range structSplitAtTests { 1160 | t.Run("", func(t *testing.T) { 1161 | if before, after := test.input.SplitAt(test.i); !test.before.Equals(before) || !test.after.Equals(after) { 1162 | t.Errorf("expected %v, %v but got %v, %v", test.before, test.after, before, after) 1163 | } 1164 | }) 1165 | } 1166 | } 1167 | 1168 | func Test_structGroup(t *testing.T) { 1169 | for _, test := range structGroupTests { 1170 | t.Run("", func(t *testing.T) { 1171 | res := test.input.Group() 1172 | for i, v := range test.output { 1173 | if !v.EqualsOrdered(res[i]) { 1174 | t.Errorf("expected %v but got %v", v, res[i]) 1175 | } 1176 | } 1177 | }) 1178 | } 1179 | } 1180 | 1181 | func Test_structScan1(t *testing.T) { 1182 | for _, test := range structScanTests { 1183 | t.Run("", func(t *testing.T) { 1184 | if res := test.input.Scanl(test.init, test.scanfunc); !test.scanl.Equals(res) { 1185 | t.Errorf("expected %v but got %v", test.scanl, res) 1186 | } 1187 | }) 1188 | } 1189 | } 1190 | 1191 | func Test_structIsPrefixOf(t *testing.T) { 1192 | for _, test := range structIsPrefixOfTests { 1193 | t.Run("", func(t *testing.T) { 1194 | res := test.input.IsPrefixOf(test.param1) 1195 | if res != test.output { 1196 | t.Errorf("expected %v but got %v", test.output, res) 1197 | } 1198 | }) 1199 | } 1200 | } 1201 | -------------------------------------------------------------------------------- /types/Strings.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "strings" 5 | ) 6 | 7 | // Strings is a wrapper around []string 8 | //go:generate hasgo -T=string -S=Strings 9 | type Strings []string 10 | 11 | // StringReplicate creates a slice with `value` repeated `count` times 12 | func StringReplicate(count uint64, value string) (out Strings) { 13 | out = make(Strings, count) 14 | for i := uint64(0); i < count; i++ { 15 | out[i] = value 16 | } 17 | return 18 | } 19 | 20 | const ( 21 | wordSeparator = " " 22 | lineSeparator = "\n" 23 | ) 24 | 25 | // EqualsOrdered verifies that both slices contain the same elements in the same position. 26 | func (is Strings) EqualsOrdered(other Strings) bool { 27 | if len(is) != len(other) { 28 | return false 29 | } 30 | if len(is) == 0 && len(other) == 0 { 31 | return true 32 | } 33 | for i := range is { 34 | if is[i] != other[i] { 35 | return false 36 | } 37 | } 38 | return true 39 | } 40 | 41 | // Equals verifies that both slices contain the same elements, regardless of position. 42 | func (is Strings) Equals(other Strings) bool { 43 | if len(is) != len(other) { 44 | return false 45 | } 46 | if len(is) == 0 && len(other) == 0 { 47 | return true 48 | } 49 | contains := make(map[string]struct{}, 0) 50 | for _, i := range is { 51 | contains[i] = struct{}{} 52 | } 53 | for _, i := range other { 54 | if _, ok := contains[i]; !ok { 55 | return false 56 | } 57 | } 58 | return true 59 | } 60 | 61 | // Words is a wrapper around strings.Split(string, " ") 62 | func Words(s string) Strings { 63 | return split(s, wordSeparator) 64 | } 65 | 66 | // Lines is a wrapper around strings.Split(string, "\n") 67 | func Lines(s string) Strings { 68 | return split(s, lineSeparator) 69 | } 70 | 71 | func split(s, sep string) Strings { 72 | if s == "" { 73 | return Strings{} 74 | } 75 | return Strings(strings.Split(s, sep)) 76 | } 77 | -------------------------------------------------------------------------------- /types/Strings_hasgo.go: -------------------------------------------------------------------------------- 1 | // Package types contains code generated by hasgo. [DO NOT EDIT!] 2 | package types 3 | 4 | import ( 5 | "fmt" 6 | "sort" 7 | ) 8 | 9 | // =============== all.go ================= 10 | 11 | // All returns true if all elements of the slice satisfy the predicate. 12 | // Can be generated for any type. 13 | func (s Strings) All(f func(string) bool) bool { 14 | if f == nil { 15 | return false 16 | } 17 | for _, v := range s { 18 | if !f(v) { 19 | return false 20 | } 21 | } 22 | return true 23 | } 24 | 25 | // =============== any.go ================= 26 | 27 | // Any returns true if any of the elements satisfy the predicate. 28 | // Can be generated for any type. 29 | func (s Strings) Any(f func(string) bool) bool { 30 | if f == nil { 31 | return false 32 | } 33 | for _, v := range s { 34 | if f(v) { 35 | return true 36 | } 37 | } 38 | return false 39 | } 40 | 41 | // =============== break.go ================= 42 | 43 | // Break returns a tuple of any elements that do not satisfy the predicate up until the first time it passes, followed 44 | // by the rest of the elements. 45 | // Can be generated on any type. 46 | func (s Strings) Break(f func(string) bool) (before Strings, after Strings) { 47 | if f == nil { 48 | return before, s 49 | } 50 | 51 | passed := false 52 | 53 | for _, v := range s { 54 | if passed || f(v) { 55 | after = append(after, v) 56 | passed = true 57 | } else { 58 | before = append(before, v) 59 | } 60 | } 61 | 62 | return 63 | } 64 | 65 | // =============== delete.go ================= 66 | 67 | // Delete returns a slice with the first matching element 68 | // removed from the slice. 69 | // Can be generated for any type. 70 | func (s Strings) Delete(e string) (out Strings) { 71 | deleted := false 72 | for _, v := range s { 73 | if deleted || v != e { 74 | out = append(out, v) 75 | } else { 76 | deleted = true 77 | } 78 | } 79 | return 80 | } 81 | 82 | // =============== drop.go ================= 83 | 84 | // Drop returns a new Slice with the elements after the provided key. 85 | // Can be generated for any type. 86 | func (s Strings) Drop(i int) (out Strings) { 87 | for i < len(s) { 88 | out = append(out, s[i]) 89 | i++ 90 | } 91 | return 92 | } 93 | 94 | // =============== dropwhile.go ================= 95 | 96 | // DropWhile returns a new slice containing all elements after the predicate fails for the first time. 97 | // Can be generated for any type. 98 | func (s Strings) DropWhile(f func(string) bool) (out Strings) { 99 | if f == nil { 100 | return s 101 | } 102 | failed := false 103 | for _, v := range s { 104 | if failed { 105 | out = append(out, v) 106 | continue 107 | } 108 | if !f(v) { 109 | out = append(out, v) 110 | failed = true 111 | } 112 | } 113 | return 114 | } 115 | 116 | // =============== elem.go ================= 117 | 118 | // Elem returns true if the slice contains the element 119 | // Can be generated for any type. 120 | func (s Strings) Elem(el string) bool { 121 | for _, e := range s { 122 | if e == el { 123 | return true 124 | } 125 | } 126 | return false 127 | } 128 | 129 | // =============== filter.go ================= 130 | 131 | // Filter returns a slice containing only the elements that match the predicate. 132 | // Can be generated for any type. 133 | func (s Strings) Filter(f func(string) bool) (out Strings) { 134 | for _, v := range s { 135 | if f(v) { 136 | out = append(out, v) 137 | } 138 | } 139 | return 140 | } 141 | 142 | // =============== foldl.go ================= 143 | 144 | // Foldl reduces a list by iteratively applying f from left->right. Thus, for an empty slice, the result is the default zero-value. 145 | func (s Strings) Foldl(z string, f func(e1, e2 string) string) (out string) { 146 | if len(s) == 0 { 147 | return 148 | } 149 | out = f(z, s[0]) 150 | for _, v := range s[1:] { 151 | out = f(out, v) 152 | } 153 | return 154 | } 155 | 156 | // =============== foldl1.go ================= 157 | 158 | // Foldl1 reduces a list by iteratively applying f from left->right. Thus, for an empty slice, the result is the default zero-value. 159 | func (s Strings) Foldl1(f func(e1, e2 string) string) (out string) { 160 | if len(s) == 0 { 161 | return 162 | } 163 | out = s[0] 164 | for _, v := range s[1:] { 165 | out = f(out, v) 166 | } 167 | return 168 | } 169 | 170 | // =============== foldr.go ================= 171 | 172 | // Foldr reduces a list by iteratively applying f from right -> left. Thus, for an empty slice, the result is the default zero-value. 173 | func (s Strings) Foldr(e string, f func(e1, e2 string) string) (out string) { 174 | if len(s) == 0 { 175 | return 176 | } 177 | 178 | end := len(s) - 1 179 | out = f(s[end], e) 180 | 181 | for i := end - 1; i >= 0; i-- { 182 | out = f(s[i], out) 183 | } 184 | 185 | return 186 | } 187 | 188 | // =============== foldr1.go ================= 189 | 190 | // Foldr1 reduces a list by iteratively applying f from right -> left. Thus, for an empty slice, the result is the default zero-value. 191 | func (s Strings) Foldr1(f func(e1, e2 string) string) (out string) { 192 | if len(s) == 0 { 193 | return 194 | } 195 | 196 | end := len(s) - 1 197 | out = s[end] 198 | 199 | for i := end - 1; i >= 0; i-- { 200 | out = f(s[i], out) 201 | } 202 | 203 | return 204 | } 205 | 206 | // =============== group.go ================= 207 | 208 | // Group returns a list of lists where each list contains only equal elements and the concatenation of the 209 | // result is equal to the argument. 210 | // Can be generated for any type. 211 | func (s Strings) Group() (out [][]string) { 212 | current := Strings{} 213 | 214 | for i, v := range s { 215 | current = append(current, v) 216 | if i == len(s)-1 || v != s[i+1] { 217 | out = append(out, current) 218 | current = Strings{} 219 | } 220 | } 221 | 222 | return 223 | } 224 | 225 | // =============== head.go ================= 226 | 227 | // Head returns the first element in the slice. 228 | // If no element is found, returns the zero-value of the type. 229 | // Can be generated for any type. 230 | func (s Strings) Head() (out string) { 231 | if len(s) > 0 { 232 | out = s[0] 233 | } 234 | return 235 | } 236 | 237 | // =============== init.go ================= 238 | 239 | // Init takes n-1 elements from a slice, where n = len(list). 240 | // Can be generated for any type. 241 | func (s Strings) Init() (out Strings) { 242 | if len(s) == 0 { 243 | return 244 | } 245 | slicecopy := append([]string(nil), s...) 246 | return slicecopy[:len(s)-1] 247 | } 248 | 249 | // =============== inits.go ================= 250 | 251 | // Inits returns all inits of a sequence, in order of small to large, as if it were called recursively. 252 | // Can be generated for any type. 253 | func (s Strings) Inits() (out [][]string) { 254 | out = append(out, make(Strings, 0)) 255 | for i := range s { 256 | init := make(Strings, i+1) 257 | for n := 0; n <= i; n++ { 258 | init[n] = s[n] 259 | } 260 | out = append(out, init) 261 | } 262 | return 263 | } 264 | 265 | // =============== intercalate.go ================= 266 | 267 | // Intercalate inserts the method receiver slice into the function slice at each step. 268 | // Can be generated for any type. 269 | func (s Strings) Intercalate(ss [][]string) (out Strings) { 270 | for i, slice := range ss { 271 | for _, el := range slice { 272 | out = append(out, el) 273 | } 274 | if i == len(ss)-1 { 275 | break 276 | } 277 | for _, el := range s { 278 | out = append(out, el) 279 | } 280 | } 281 | return out 282 | } 283 | 284 | // =============== intersperse.go ================= 285 | 286 | // Intersperse inserts the receiving value between each element of the method receiver. 287 | // Can be generated for any type. 288 | func (s Strings) Intersperse(value string) (out Strings) { 289 | for i, el := range s { 290 | out = append(out, el) 291 | if i == len(s)-1 { 292 | break 293 | } 294 | out = append(out, value) 295 | } 296 | return 297 | } 298 | 299 | // =============== isprefixof.go ================= 300 | 301 | // IsPrefixOf returns true if the current sliceType is a prefix of the passed one. 302 | // Can be generated for any time. 303 | func (s Strings) IsPrefixOf(in Strings) bool { 304 | if len(s) > len(in) { 305 | return false 306 | } 307 | for i, v := range s { 308 | if in[i] != v { 309 | return false 310 | } 311 | } 312 | return true 313 | } 314 | 315 | // =============== last.go ================= 316 | 317 | // Last returns the last element in the slice 318 | // If no element is found, returns the zero-value of the type 319 | // Can be generated for any type. 320 | func (s Strings) Last() (out string) { 321 | if len(s) > 0 { 322 | out = s[len(s)-1] 323 | } 324 | return 325 | } 326 | 327 | // =============== length.go ================= 328 | 329 | // Length returns the length (len) of a slice. 330 | // Can be generated for any type. 331 | func (s Strings) Length() int { 332 | return len(s) 333 | } 334 | 335 | // =============== map.go ================= 336 | 337 | // Map return a new slice with the map operation applied to each element. 338 | // Can be generated for any type. 339 | func (s Strings) Map(f func(string) string) (out Strings) { 340 | if f == nil { 341 | return s 342 | } 343 | for _, v := range s { 344 | out = append(out, f(v)) 345 | } 346 | return 347 | } 348 | 349 | // =============== maximumby.go ================= 350 | 351 | // MaximumBy returns the maximum elements according to a custom comparator. 352 | // Can be generated for any type. 353 | func (s Strings) MaximumBy(f func(e1, e2 string) string) (max string) { 354 | if len(s) == 0 { 355 | return 356 | } 357 | max = s[0] 358 | for _, el := range s[1:] { 359 | max = f(max, el) 360 | } 361 | return 362 | } 363 | 364 | // =============== modes.go ================= 365 | 366 | // Modes returns the elements with highest frequency in the slice. 367 | // Can be generated for any type. 368 | func (s Strings) Modes() (out Strings) { 369 | if len(s) == 0 { 370 | return 371 | } 372 | 373 | counts := make(map[string]int) 374 | for _, v := range s { 375 | counts[v]++ 376 | } 377 | 378 | var max int 379 | for _, v := range counts { 380 | if v > max { 381 | max = v 382 | } 383 | } 384 | 385 | for k, v := range counts { 386 | if v == max { 387 | out = append(out, k) 388 | } 389 | } 390 | 391 | return 392 | } 393 | 394 | // =============== nub.go ================= 395 | 396 | // Nub returns a slice containing only the unique elements of the receiver. 397 | // The order of the elements is preserved. 398 | // Can be generated for any type. 399 | func (s Strings) Nub() (out Strings) { 400 | if len(s) == 0 { 401 | return 402 | } 403 | 404 | contains := make(map[string]struct{}) 405 | for _, v := range s { 406 | if _, ok := contains[v]; !ok { 407 | contains[v] = struct{}{} 408 | out = append(out, v) 409 | } 410 | } 411 | return 412 | } 413 | 414 | // =============== null.go ================= 415 | 416 | // Null returns true the slice is empty. 417 | // Can be generated for any type. 418 | func (s Strings) Null() bool { 419 | return len(s) == 0 420 | } 421 | 422 | // =============== reverse.go ================= 423 | 424 | // Reverse returns the reversed slice. 425 | // Can be generated for any type. 426 | func (s Strings) Reverse() (out Strings) { 427 | for i := len(s) - 1; i >= 0; i-- { 428 | out = append(out, s[i]) 429 | } 430 | return 431 | } 432 | 433 | // =============== scanl.go ================= 434 | 435 | // Scanl reduces a list by iteratively applying f from left->right and then returns each iteration in a slice. 436 | func (s Strings) Scanl(e string, f func(e1, e2 string) string) (out Strings) { 437 | if len(s) == 0 { 438 | return 439 | } 440 | 441 | out = append(out, e) 442 | last := e 443 | 444 | for _, v := range s { 445 | last = f(last, v) 446 | out = append(out, last) 447 | } 448 | 449 | return 450 | } 451 | 452 | // =============== sort.go ================= 453 | 454 | // Sort is a wrapper around go sort function. 455 | // Can be generated for any type. 456 | func (s Strings) Sort() Strings { 457 | out := make(Strings, len(s)) 458 | copy(out, s) 459 | sort.Slice(out, func(i, j int) bool { 460 | return out[i] < out[j] 461 | }) 462 | return out 463 | } 464 | 465 | // =============== span.go ================= 466 | 467 | // Span returns a tuple of any elements that satisfy the predicate up until the first failure, followed by 468 | // the rest of the elements. 469 | // Can be generated for any type. 470 | func (s Strings) Span(f func(string) bool) (before Strings, after Strings) { 471 | if f == nil { 472 | return before, s 473 | } 474 | 475 | failed := false 476 | 477 | for _, v := range s { 478 | if failed || !f(v) { 479 | after = append(after, v) 480 | failed = true 481 | } else { 482 | before = append(before, v) 483 | } 484 | } 485 | 486 | return 487 | } 488 | 489 | // =============== splitat.go ================= 490 | 491 | // SplitAt splits the slice at the given index, returning before and after as a tuple. 492 | // Can be generated for any type. 493 | func (s Strings) SplitAt(i int) (before, after Strings) { 494 | for k, v := range s { 495 | if k < i { 496 | before = append(before, v) 497 | } else { 498 | after = append(after, v) 499 | } 500 | } 501 | return 502 | } 503 | 504 | // =============== sum.go ================= 505 | 506 | // Sum returns the sum of all elements in the slice. 507 | // Can be generated for any number type. 508 | func (s Strings) Sum() string { 509 | var sum string 510 | for _, v := range s { 511 | sum += v 512 | } 513 | return sum 514 | } 515 | 516 | // =============== tail.go ================= 517 | 518 | // Tail takes [1 -> n] elements from a slice, where n = len(list) 519 | // Returns an empty slice if there are less than 2 elements in slice 520 | // Can be generated for any type. 521 | func (s Strings) Tail() (out Strings) { 522 | if len(s) <= 1 { 523 | return 524 | } 525 | slicecopy := append([]string(nil), s...) 526 | return slicecopy[1:] 527 | } 528 | 529 | // =============== tails.go ================= 530 | 531 | // Tails returns all tails of a sequence, in order of large to small, as if it were called recursively. 532 | // Can be generated for any type. 533 | func (s Strings) Tails() (out [][]string) { 534 | slicecopy := append([]string(nil), s...) 535 | for range s { 536 | out = append(out, slicecopy) 537 | slicecopy = slicecopy[1:] 538 | } 539 | out = append(out, make(Strings, 0)) 540 | return 541 | } 542 | 543 | // =============== take.go ================= 544 | 545 | // Take takes the first n elements of the slice, or the entire slice if n > len(slice). 546 | // Can be generated for any type. 547 | func (s Strings) Take(n uint64) (out Strings) { 548 | if len(s) == 0 { 549 | return 550 | } 551 | out = make(Strings, len(s)) 552 | copy(out, s) 553 | if n < uint64(len(s)) { 554 | return out[:n] 555 | } 556 | return 557 | } 558 | 559 | // =============== takewhile.go ================= 560 | 561 | // TakeWhile continues appending to the output as long as the predicate is satisfied. 562 | // Can be generated for any type. 563 | func (s Strings) TakeWhile(p func(string) bool) (out Strings) { 564 | if len(s) == 0 { 565 | return 566 | } 567 | for _, e := range s { 568 | if !p(e) { 569 | return 570 | } 571 | out = append(out, e) 572 | } 573 | return 574 | } 575 | 576 | // =============== uncons.go ================= 577 | 578 | // Uncons decomposes a slice into the head and tail component. 579 | // Can be generated for any type. 580 | func (s Strings) Uncons() (head string, tail Strings) { 581 | return s.Head(), s.Tail() 582 | } 583 | 584 | // =============== unlines.go ================= 585 | 586 | // Unlines joins together the string representation of the slice with newlines after each element. 587 | // Can be generated for any type. 588 | func (s Strings) Unlines() (out string) { 589 | for i, v := range s { 590 | out += fmt.Sprintf("%v", v) 591 | if i != len(s)-1 { 592 | out += "\n" 593 | } 594 | } 595 | return 596 | } 597 | 598 | // =============== unwords.go ================= 599 | 600 | // Unwords joins together the string representation of the slice with newlines after each element. 601 | // Can be generated for any type. 602 | func (s Strings) Unwords() (out string) { 603 | for i, v := range s { 604 | out += fmt.Sprintf("%v", v) 605 | if i != len(s)-1 { 606 | out += " " 607 | } 608 | } 609 | return 610 | } 611 | -------------------------------------------------------------------------------- /types/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/DylanMeeus/hasgo/types 2 | 3 | go 1.13 4 | -------------------------------------------------------------------------------- /types/persons_hasgo.go: -------------------------------------------------------------------------------- 1 | // Package types contains code generated by hasgo. [DO NOT EDIT!] 2 | package types 3 | 4 | import ( 5 | "fmt" 6 | ) 7 | 8 | // =============== all.go ================= 9 | 10 | // All returns true if all elements of the slice satisfy the predicate. 11 | // Can be generated for any type. 12 | func (s persons) All(f func(person) bool) bool { 13 | if f == nil { 14 | return false 15 | } 16 | for _, v := range s { 17 | if !f(v) { 18 | return false 19 | } 20 | } 21 | return true 22 | } 23 | 24 | // =============== any.go ================= 25 | 26 | // Any returns true if any of the elements satisfy the predicate. 27 | // Can be generated for any type. 28 | func (s persons) Any(f func(person) bool) bool { 29 | if f == nil { 30 | return false 31 | } 32 | for _, v := range s { 33 | if f(v) { 34 | return true 35 | } 36 | } 37 | return false 38 | } 39 | 40 | // =============== break.go ================= 41 | 42 | // Break returns a tuple of any elements that do not satisfy the predicate up until the first time it passes, followed 43 | // by the rest of the elements. 44 | // Can be generated on any type. 45 | func (s persons) Break(f func(person) bool) (before persons, after persons) { 46 | if f == nil { 47 | return before, s 48 | } 49 | 50 | passed := false 51 | 52 | for _, v := range s { 53 | if passed || f(v) { 54 | after = append(after, v) 55 | passed = true 56 | } else { 57 | before = append(before, v) 58 | } 59 | } 60 | 61 | return 62 | } 63 | 64 | // =============== delete.go ================= 65 | 66 | // Delete returns a slice with the first matching element 67 | // removed from the slice. 68 | // Can be generated for any type. 69 | func (s persons) Delete(e person) (out persons) { 70 | deleted := false 71 | for _, v := range s { 72 | if deleted || v != e { 73 | out = append(out, v) 74 | } else { 75 | deleted = true 76 | } 77 | } 78 | return 79 | } 80 | 81 | // =============== drop.go ================= 82 | 83 | // Drop returns a new Slice with the elements after the provided key. 84 | // Can be generated for any type. 85 | func (s persons) Drop(i int) (out persons) { 86 | for i < len(s) { 87 | out = append(out, s[i]) 88 | i++ 89 | } 90 | return 91 | } 92 | 93 | // =============== dropwhile.go ================= 94 | 95 | // DropWhile returns a new slice containing all elements after the predicate fails for the first time. 96 | // Can be generated for any type. 97 | func (s persons) DropWhile(f func(person) bool) (out persons) { 98 | if f == nil { 99 | return s 100 | } 101 | failed := false 102 | for _, v := range s { 103 | if failed { 104 | out = append(out, v) 105 | continue 106 | } 107 | if !f(v) { 108 | out = append(out, v) 109 | failed = true 110 | } 111 | } 112 | return 113 | } 114 | 115 | // =============== elem.go ================= 116 | 117 | // Elem returns true if the slice contains the element 118 | // Can be generated for any type. 119 | func (s persons) Elem(el person) bool { 120 | for _, e := range s { 121 | if e == el { 122 | return true 123 | } 124 | } 125 | return false 126 | } 127 | 128 | // =============== filter.go ================= 129 | 130 | // Filter returns a slice containing only the elements that match the predicate. 131 | // Can be generated for any type. 132 | func (s persons) Filter(f func(person) bool) (out persons) { 133 | for _, v := range s { 134 | if f(v) { 135 | out = append(out, v) 136 | } 137 | } 138 | return 139 | } 140 | 141 | // =============== foldl.go ================= 142 | 143 | // Foldl reduces a list by iteratively applying f from left->right. Thus, for an empty slice, the result is the default zero-value. 144 | func (s persons) Foldl(z person, f func(e1, e2 person) person) (out person) { 145 | if len(s) == 0 { 146 | return 147 | } 148 | out = f(z, s[0]) 149 | for _, v := range s[1:] { 150 | out = f(out, v) 151 | } 152 | return 153 | } 154 | 155 | // =============== foldl1.go ================= 156 | 157 | // Foldl1 reduces a list by iteratively applying f from left->right. Thus, for an empty slice, the result is the default zero-value. 158 | func (s persons) Foldl1(f func(e1, e2 person) person) (out person) { 159 | if len(s) == 0 { 160 | return 161 | } 162 | out = s[0] 163 | for _, v := range s[1:] { 164 | out = f(out, v) 165 | } 166 | return 167 | } 168 | 169 | // =============== foldr.go ================= 170 | 171 | // Foldr reduces a list by iteratively applying f from right -> left. Thus, for an empty slice, the result is the default zero-value. 172 | func (s persons) Foldr(e person, f func(e1, e2 person) person) (out person) { 173 | if len(s) == 0 { 174 | return 175 | } 176 | 177 | end := len(s) - 1 178 | out = f(s[end], e) 179 | 180 | for i := end - 1; i >= 0; i-- { 181 | out = f(s[i], out) 182 | } 183 | 184 | return 185 | } 186 | 187 | // =============== foldr1.go ================= 188 | 189 | // Foldr1 reduces a list by iteratively applying f from right -> left. Thus, for an empty slice, the result is the default zero-value. 190 | func (s persons) Foldr1(f func(e1, e2 person) person) (out person) { 191 | if len(s) == 0 { 192 | return 193 | } 194 | 195 | end := len(s) - 1 196 | out = s[end] 197 | 198 | for i := end - 1; i >= 0; i-- { 199 | out = f(s[i], out) 200 | } 201 | 202 | return 203 | } 204 | 205 | // =============== group.go ================= 206 | 207 | // Group returns a list of lists where each list contains only equal elements and the concatenation of the 208 | // result is equal to the argument. 209 | // Can be generated for any type. 210 | func (s persons) Group() (out [][]person) { 211 | current := persons{} 212 | 213 | for i, v := range s { 214 | current = append(current, v) 215 | if i == len(s)-1 || v != s[i+1] { 216 | out = append(out, current) 217 | current = persons{} 218 | } 219 | } 220 | 221 | return 222 | } 223 | 224 | // =============== head.go ================= 225 | 226 | // Head returns the first element in the slice. 227 | // If no element is found, returns the zero-value of the type. 228 | // Can be generated for any type. 229 | func (s persons) Head() (out person) { 230 | if len(s) > 0 { 231 | out = s[0] 232 | } 233 | return 234 | } 235 | 236 | // =============== init.go ================= 237 | 238 | // Init takes n-1 elements from a slice, where n = len(list). 239 | // Can be generated for any type. 240 | func (s persons) Init() (out persons) { 241 | if len(s) == 0 { 242 | return 243 | } 244 | slicecopy := append([]person(nil), s...) 245 | return slicecopy[:len(s)-1] 246 | } 247 | 248 | // =============== inits.go ================= 249 | 250 | // Inits returns all inits of a sequence, in order of small to large, as if it were called recursively. 251 | // Can be generated for any type. 252 | func (s persons) Inits() (out [][]person) { 253 | out = append(out, make(persons, 0)) 254 | for i := range s { 255 | init := make(persons, i+1) 256 | for n := 0; n <= i; n++ { 257 | init[n] = s[n] 258 | } 259 | out = append(out, init) 260 | } 261 | return 262 | } 263 | 264 | // =============== intercalate.go ================= 265 | 266 | // Intercalate inserts the method receiver slice into the function slice at each step. 267 | // Can be generated for any type. 268 | func (s persons) Intercalate(ss [][]person) (out persons) { 269 | for i, slice := range ss { 270 | for _, el := range slice { 271 | out = append(out, el) 272 | } 273 | if i == len(ss)-1 { 274 | break 275 | } 276 | for _, el := range s { 277 | out = append(out, el) 278 | } 279 | } 280 | return out 281 | } 282 | 283 | // =============== intersperse.go ================= 284 | 285 | // Intersperse inserts the receiving value between each element of the method receiver. 286 | // Can be generated for any type. 287 | func (s persons) Intersperse(value person) (out persons) { 288 | for i, el := range s { 289 | out = append(out, el) 290 | if i == len(s)-1 { 291 | break 292 | } 293 | out = append(out, value) 294 | } 295 | return 296 | } 297 | 298 | // =============== isprefixof.go ================= 299 | 300 | // IsPrefixOf returns true if the current sliceType is a prefix of the passed one. 301 | // Can be generated for any time. 302 | func (s persons) IsPrefixOf(in persons) bool { 303 | if len(s) > len(in) { 304 | return false 305 | } 306 | for i, v := range s { 307 | if in[i] != v { 308 | return false 309 | } 310 | } 311 | return true 312 | } 313 | 314 | // =============== last.go ================= 315 | 316 | // Last returns the last element in the slice 317 | // If no element is found, returns the zero-value of the type 318 | // Can be generated for any type. 319 | func (s persons) Last() (out person) { 320 | if len(s) > 0 { 321 | out = s[len(s)-1] 322 | } 323 | return 324 | } 325 | 326 | // =============== length.go ================= 327 | 328 | // Length returns the length (len) of a slice. 329 | // Can be generated for any type. 330 | func (s persons) Length() int { 331 | return len(s) 332 | } 333 | 334 | // =============== map.go ================= 335 | 336 | // Map return a new slice with the map operation applied to each element. 337 | // Can be generated for any type. 338 | func (s persons) Map(f func(person) person) (out persons) { 339 | if f == nil { 340 | return s 341 | } 342 | for _, v := range s { 343 | out = append(out, f(v)) 344 | } 345 | return 346 | } 347 | 348 | // =============== maximumby.go ================= 349 | 350 | // MaximumBy returns the maximum elements according to a custom comparator. 351 | // Can be generated for any type. 352 | func (s persons) MaximumBy(f func(e1, e2 person) person) (max person) { 353 | if len(s) == 0 { 354 | return 355 | } 356 | max = s[0] 357 | for _, el := range s[1:] { 358 | max = f(max, el) 359 | } 360 | return 361 | } 362 | 363 | // =============== modes.go ================= 364 | 365 | // Modes returns the elements with highest frequency in the slice. 366 | // Can be generated for any type. 367 | func (s persons) Modes() (out persons) { 368 | if len(s) == 0 { 369 | return 370 | } 371 | 372 | counts := make(map[person]int) 373 | for _, v := range s { 374 | counts[v]++ 375 | } 376 | 377 | var max int 378 | for _, v := range counts { 379 | if v > max { 380 | max = v 381 | } 382 | } 383 | 384 | for k, v := range counts { 385 | if v == max { 386 | out = append(out, k) 387 | } 388 | } 389 | 390 | return 391 | } 392 | 393 | // =============== nub.go ================= 394 | 395 | // Nub returns a slice containing only the unique elements of the receiver. 396 | // The order of the elements is preserved. 397 | // Can be generated for any type. 398 | func (s persons) Nub() (out persons) { 399 | if len(s) == 0 { 400 | return 401 | } 402 | 403 | contains := make(map[person]struct{}) 404 | for _, v := range s { 405 | if _, ok := contains[v]; !ok { 406 | contains[v] = struct{}{} 407 | out = append(out, v) 408 | } 409 | } 410 | return 411 | } 412 | 413 | // =============== null.go ================= 414 | 415 | // Null returns true the slice is empty. 416 | // Can be generated for any type. 417 | func (s persons) Null() bool { 418 | return len(s) == 0 419 | } 420 | 421 | // =============== reverse.go ================= 422 | 423 | // Reverse returns the reversed slice. 424 | // Can be generated for any type. 425 | func (s persons) Reverse() (out persons) { 426 | for i := len(s) - 1; i >= 0; i-- { 427 | out = append(out, s[i]) 428 | } 429 | return 430 | } 431 | 432 | // =============== scanl.go ================= 433 | 434 | // Scanl reduces a list by iteratively applying f from left->right and then returns each iteration in a slice. 435 | func (s persons) Scanl(e person, f func(e1, e2 person) person) (out persons) { 436 | if len(s) == 0 { 437 | return 438 | } 439 | 440 | out = append(out, e) 441 | last := e 442 | 443 | for _, v := range s { 444 | last = f(last, v) 445 | out = append(out, last) 446 | } 447 | 448 | return 449 | } 450 | 451 | // =============== span.go ================= 452 | 453 | // Span returns a tuple of any elements that satisfy the predicate up until the first failure, followed by 454 | // the rest of the elements. 455 | // Can be generated for any type. 456 | func (s persons) Span(f func(person) bool) (before persons, after persons) { 457 | if f == nil { 458 | return before, s 459 | } 460 | 461 | failed := false 462 | 463 | for _, v := range s { 464 | if failed || !f(v) { 465 | after = append(after, v) 466 | failed = true 467 | } else { 468 | before = append(before, v) 469 | } 470 | } 471 | 472 | return 473 | } 474 | 475 | // =============== splitat.go ================= 476 | 477 | // SplitAt splits the slice at the given index, returning before and after as a tuple. 478 | // Can be generated for any type. 479 | func (s persons) SplitAt(i int) (before, after persons) { 480 | for k, v := range s { 481 | if k < i { 482 | before = append(before, v) 483 | } else { 484 | after = append(after, v) 485 | } 486 | } 487 | return 488 | } 489 | 490 | // =============== tail.go ================= 491 | 492 | // Tail takes [1 -> n] elements from a slice, where n = len(list) 493 | // Returns an empty slice if there are less than 2 elements in slice 494 | // Can be generated for any type. 495 | func (s persons) Tail() (out persons) { 496 | if len(s) <= 1 { 497 | return 498 | } 499 | slicecopy := append([]person(nil), s...) 500 | return slicecopy[1:] 501 | } 502 | 503 | // =============== tails.go ================= 504 | 505 | // Tails returns all tails of a sequence, in order of large to small, as if it were called recursively. 506 | // Can be generated for any type. 507 | func (s persons) Tails() (out [][]person) { 508 | slicecopy := append([]person(nil), s...) 509 | for range s { 510 | out = append(out, slicecopy) 511 | slicecopy = slicecopy[1:] 512 | } 513 | out = append(out, make(persons, 0)) 514 | return 515 | } 516 | 517 | // =============== take.go ================= 518 | 519 | // Take takes the first n elements of the slice, or the entire slice if n > len(slice). 520 | // Can be generated for any type. 521 | func (s persons) Take(n uint64) (out persons) { 522 | if len(s) == 0 { 523 | return 524 | } 525 | out = make(persons, len(s)) 526 | copy(out, s) 527 | if n < uint64(len(s)) { 528 | return out[:n] 529 | } 530 | return 531 | } 532 | 533 | // =============== takewhile.go ================= 534 | 535 | // TakeWhile continues appending to the output as long as the predicate is satisfied. 536 | // Can be generated for any type. 537 | func (s persons) TakeWhile(p func(person) bool) (out persons) { 538 | if len(s) == 0 { 539 | return 540 | } 541 | for _, e := range s { 542 | if !p(e) { 543 | return 544 | } 545 | out = append(out, e) 546 | } 547 | return 548 | } 549 | 550 | // =============== uncons.go ================= 551 | 552 | // Uncons decomposes a slice into the head and tail component. 553 | // Can be generated for any type. 554 | func (s persons) Uncons() (head person, tail persons) { 555 | return s.Head(), s.Tail() 556 | } 557 | 558 | // =============== unlines.go ================= 559 | 560 | // Unlines joins together the string representation of the slice with newlines after each element. 561 | // Can be generated for any type. 562 | func (s persons) Unlines() (out string) { 563 | for i, v := range s { 564 | out += fmt.Sprintf("%v", v) 565 | if i != len(s)-1 { 566 | out += "\n" 567 | } 568 | } 569 | return 570 | } 571 | 572 | // =============== unwords.go ================= 573 | 574 | // Unwords joins together the string representation of the slice with newlines after each element. 575 | // Can be generated for any type. 576 | func (s persons) Unwords() (out string) { 577 | for i, v := range s { 578 | out += fmt.Sprintf("%v", v) 579 | if i != len(s)-1 { 580 | out += " " 581 | } 582 | } 583 | return 584 | } 585 | --------------------------------------------------------------------------------