Merge Go Work
This commit is contained in:
parent
b8814259b5
commit
9e58d17c5c
46
go/atbash-cipher/README.md
Normal file
46
go/atbash-cipher/README.md
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
# Atbash Cipher
|
||||||
|
|
||||||
|
Create an implementation of the atbash cipher, an ancient encryption system created in the Middle East.
|
||||||
|
|
||||||
|
The Atbash cipher is a simple substitution cipher that relies on
|
||||||
|
transposing all the letters in the alphabet such that the resulting
|
||||||
|
alphabet is backwards. The first letter is replaced with the last
|
||||||
|
letter, the second with the second-last, and so on.
|
||||||
|
|
||||||
|
An Atbash cipher for the Latin alphabet would be as follows:
|
||||||
|
|
||||||
|
```plain
|
||||||
|
Plain: abcdefghijklmnopqrstuvwxyz
|
||||||
|
Cipher: zyxwvutsrqponmlkjihgfedcba
|
||||||
|
```
|
||||||
|
|
||||||
|
It is a very weak cipher because it only has one possible key, and it is
|
||||||
|
a simple monoalphabetic substitution cipher. However, this may not have
|
||||||
|
been an issue in the cipher's time.
|
||||||
|
|
||||||
|
Ciphertext is written out in groups of fixed length, the traditional group size
|
||||||
|
being 5 letters, and punctuation is excluded. This is to make it harder to guess
|
||||||
|
things based on word boundaries.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
- Encoding `test` gives `gvhg`
|
||||||
|
- Decoding `gvhg` gives `test`
|
||||||
|
- Decoding `gsvjf rxpyi ldmul cqfnk hlevi gsvoz abwlt` gives `The quick brown fox jumps over the lazy dog.`
|
||||||
|
|
||||||
|
To run the tests simply run the command `go test` in the exercise directory.
|
||||||
|
|
||||||
|
If the test suite contains benchmarks, you can run these with the `-bench`
|
||||||
|
flag:
|
||||||
|
|
||||||
|
go test -bench .
|
||||||
|
|
||||||
|
For more detailed info about the Go track see the [help
|
||||||
|
page](http://exercism.io/languages/go).
|
||||||
|
|
||||||
|
## Source
|
||||||
|
|
||||||
|
Wikipedia [http://en.wikipedia.org/wiki/Atbash](http://en.wikipedia.org/wiki/Atbash)
|
||||||
|
|
||||||
|
## Submitting Incomplete Problems
|
||||||
|
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
||||||
|
|
36
go/atbash-cipher/atbash.go
Normal file
36
go/atbash-cipher/atbash.go
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package atbash
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
func Atbash(s string) string {
|
||||||
|
s = strings.ToLower(s)
|
||||||
|
var v []byte
|
||||||
|
var b, iter int
|
||||||
|
for i := range s {
|
||||||
|
sv := int(s[i])
|
||||||
|
switch {
|
||||||
|
case sv < 48:
|
||||||
|
continue
|
||||||
|
case sv >= 48 && sv <= 57:
|
||||||
|
b = sv
|
||||||
|
case sv < 109:
|
||||||
|
b = 110 + (109 - sv)
|
||||||
|
case sv == 109:
|
||||||
|
b = 110
|
||||||
|
case sv == 110:
|
||||||
|
b = 109
|
||||||
|
case sv > 110:
|
||||||
|
b = 109 - (sv - 110)
|
||||||
|
}
|
||||||
|
v = append(v, byte(b))
|
||||||
|
iter++
|
||||||
|
if iter == 5 {
|
||||||
|
v = append(v, ' ')
|
||||||
|
iter = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if iter == 0 {
|
||||||
|
return string(v)[:len(string(v))-1]
|
||||||
|
}
|
||||||
|
return string(v)
|
||||||
|
}
|
40
go/atbash-cipher/atbash_cipher_test.go
Normal file
40
go/atbash-cipher/atbash_cipher_test.go
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package atbash
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
var tests = []struct {
|
||||||
|
expected string
|
||||||
|
s string
|
||||||
|
}{
|
||||||
|
{"ml", "no"},
|
||||||
|
{"ml", "no"},
|
||||||
|
{"bvh", "yes"},
|
||||||
|
{"lnt", "OMG"},
|
||||||
|
{"lnt", "O M G"},
|
||||||
|
{"nrmwy oldrm tob", "mindblowingly"},
|
||||||
|
{"gvhgr mt123 gvhgr mt", "Testing, 1 2 3, testing."},
|
||||||
|
{"gifgs rhurx grlm", "Truth is fiction."},
|
||||||
|
{"gsvjf rxpyi ldmul cqfnk hlevi gsvoz abwlt", "The quick brown fox jumps over the lazy dog."},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAtbash(t *testing.T) {
|
||||||
|
for _, test := range tests {
|
||||||
|
actual := Atbash(test.s)
|
||||||
|
if actual != test.expected {
|
||||||
|
t.Errorf("Atbash(%s): expected %s, actual %s", test.s, test.expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkAtbash(b *testing.B) {
|
||||||
|
b.StopTimer()
|
||||||
|
for _, test := range tests {
|
||||||
|
b.StartTimer()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
Atbash(test.s)
|
||||||
|
}
|
||||||
|
|
||||||
|
b.StopTimer()
|
||||||
|
}
|
||||||
|
}
|
BIN
go/atbash-cipher/cmd/cmd
Executable file
BIN
go/atbash-cipher/cmd/cmd
Executable file
Binary file not shown.
11
go/atbash-cipher/cmd/main.go
Normal file
11
go/atbash-cipher/cmd/main.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"../../atbash-cipher"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
fmt.Println(atbash.Atbash("mindblowingly"))
|
||||||
|
}
|
@ -1 +1 @@
|
|||||||
custom-set
|
prime-factors
|
Binary file not shown.
@ -11,9 +11,9 @@ func main() {
|
|||||||
s1 := stringset.NewFromSlice([]string{"a"})
|
s1 := stringset.NewFromSlice([]string{"a"})
|
||||||
addAndOutput(s1, "b")
|
addAndOutput(s1, "b")
|
||||||
addAndOutput(s1, "d")
|
addAndOutput(s1, "d")
|
||||||
|
addAndOutput(s1, "c")
|
||||||
s1.PrettyPrint()
|
s1.PrettyPrint()
|
||||||
return
|
return
|
||||||
addAndOutput(s1, "c")
|
|
||||||
addAndOutput(s1, "0")
|
addAndOutput(s1, "0")
|
||||||
addAndOutput(s1, "aa")
|
addAndOutput(s1, "aa")
|
||||||
addAndOutput(s1, "aaa")
|
addAndOutput(s1, "aaa")
|
||||||
|
@ -27,7 +27,6 @@ package stringset
|
|||||||
// Format the empty set as {}.
|
// Format the empty set as {}.
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -167,17 +166,13 @@ func TestEqual(t *testing.T) {
|
|||||||
// helper for testing Add, Delete
|
// helper for testing Add, Delete
|
||||||
func testEleOp(name string, op func(Set, string), cases []eleOpCase, t *testing.T) {
|
func testEleOp(name string, op func(Set, string), cases []eleOpCase, t *testing.T) {
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
fmt.Print("Running Test Case: ")
|
|
||||||
fmt.Println(tc)
|
|
||||||
s := NewFromSlice(tc.set)
|
s := NewFromSlice(tc.set)
|
||||||
op(s, tc.ele)
|
op(s, tc.ele)
|
||||||
want := NewFromSlice(tc.want)
|
want := NewFromSlice(tc.want)
|
||||||
if !Equal(s, want) {
|
if !Equal(s, want) {
|
||||||
fmt.Println(s.String())
|
|
||||||
t.Fatalf("%v %s %q = %v, want %v",
|
t.Fatalf("%v %s %q = %v, want %v",
|
||||||
NewFromSlice(tc.set), name, tc.ele, s, want)
|
NewFromSlice(tc.set), name, tc.ele, s, want)
|
||||||
}
|
}
|
||||||
fmt.Println("=== Done ===")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@ package stringset
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -45,20 +44,12 @@ func (s Set) Add(v string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !s.Has(v) {
|
if !s.Has(v) {
|
||||||
bef := "Current Top Node: " + s.top.value + ";L:" + s.top.getLeftValue() + ";R:" + s.top.getRightValue()
|
|
||||||
newNode := s.top.Add(&Node{value: v})
|
newNode := s.top.Add(&Node{value: v})
|
||||||
fmt.Println(bef)
|
|
||||||
fmt.Println("Current New Node: " + newNode.value + ";L:" + newNode.getLeftValue() + ";R:" + newNode.getRightValue())
|
|
||||||
fmt.Printf("newNode.left: %v (%v)\n", &newNode.left, newNode.left)
|
|
||||||
s.top.value = newNode.value
|
s.top.value = newNode.value
|
||||||
s.top.left = newNode.left
|
s.top.left = newNode.left
|
||||||
s.top.right = newNode.right
|
s.top.right = newNode.right
|
||||||
fmt.Println("Current Top Node: " + s.top.value + ";L:" + s.top.getLeftValue() + ";R:" + s.top.getRightValue())
|
|
||||||
fmt.Printf("s.top.left: %v (%v)\n", &s.top.left, s.top.left)
|
|
||||||
fmt.Println("Add Done")
|
|
||||||
|
|
||||||
//s.top = s.top.Add(newNode)
|
|
||||||
//fmt.Println("Current Top Node: " + s.top.value + ";L:" + s.top.getLeftValue() + ";R:" + s.top.getRightValue())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,63 +265,43 @@ func (sv *Node) findHome(v *Node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (sv *Node) Add(n *Node) *Node {
|
func (sv *Node) Add(n *Node) *Node {
|
||||||
fmt.Println("1 Adding at Node " + sv.value)
|
|
||||||
cmp := strings.Compare(n.value, sv.value)
|
cmp := strings.Compare(n.value, sv.value)
|
||||||
if cmp < 0 {
|
if cmp < 0 {
|
||||||
fmt.Println("2 checking to left")
|
|
||||||
if sv.left == nil {
|
if sv.left == nil {
|
||||||
fmt.Println("3 left is nil, add it")
|
|
||||||
sv.left = n
|
sv.left = n
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("--> 4 recurse left")
|
|
||||||
sv.left = sv.left.Add(n)
|
sv.left = sv.left.Add(n)
|
||||||
fmt.Println("<-- 5 added to left")
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("6 checking to right")
|
|
||||||
if sv.right == nil {
|
if sv.right == nil {
|
||||||
fmt.Println("7 right is nil, add it")
|
|
||||||
sv.right = n
|
sv.right = n
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("--> 8 recurse right")
|
|
||||||
sv.right = sv.right.Add(n)
|
sv.right = sv.right.Add(n)
|
||||||
fmt.Println("<-- 9 added to right")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("10 let's balance now (sv: " + sv.value + ")")
|
newVal := sv
|
||||||
|
/* TODO: Fix the tree balancing
|
||||||
balance := GetBalance(sv)
|
balance := GetBalance(sv)
|
||||||
// left left unbalance
|
// left left unbalance
|
||||||
fmt.Println("11 balance: " + strconv.Itoa(balance))
|
if balance > 1 && strings.Compare(n.value, sv.getLeftValue()) < 0 {
|
||||||
newVal := sv
|
|
||||||
if balance > 1 && strings.Compare(n.value, sv.getLeftValue()) < 0 { // < sv.left.value {
|
|
||||||
fmt.Println("12 Left Left")
|
|
||||||
newVal = RightRotate(sv)
|
newVal = RightRotate(sv)
|
||||||
fmt.Println("13")
|
|
||||||
}
|
}
|
||||||
// right right unbalance
|
// right right unbalance
|
||||||
if balance < -1 && strings.Compare(n.value, sv.getRightValue()) > 0 { //n.value > sv.right.value {
|
if balance < -1 && strings.Compare(n.value, sv.getRightValue()) > 0 {
|
||||||
fmt.Println("14 Right Right")
|
|
||||||
newVal = LeftRotate(sv)
|
newVal = LeftRotate(sv)
|
||||||
fmt.Println("15")
|
|
||||||
}
|
}
|
||||||
// left right unbalance
|
// left right unbalance
|
||||||
if balance > 1 && strings.Compare(n.value, sv.getLeftValue()) > 0 { //n.value > sv.left.value {
|
if balance > 1 && strings.Compare(n.value, sv.getLeftValue()) > 0 {
|
||||||
fmt.Println("16 Left Right")
|
|
||||||
sv.left = LeftRotate(sv.left)
|
sv.left = LeftRotate(sv.left)
|
||||||
fmt.Println("17")
|
|
||||||
newVal = RightRotate(sv)
|
newVal = RightRotate(sv)
|
||||||
fmt.Println("18")
|
|
||||||
}
|
}
|
||||||
// right left unbalance
|
// right left unbalance
|
||||||
if balance < -1 && strings.Compare(n.value, sv.getRightValue()) < 0 { //n.value < sv.right.value {
|
if balance < -1 && strings.Compare(n.value, sv.getRightValue()) < 0 {
|
||||||
fmt.Println("19 Right Left")
|
|
||||||
sv.right = RightRotate(sv.right)
|
sv.right = RightRotate(sv.right)
|
||||||
fmt.Println("20")
|
|
||||||
newVal = LeftRotate(sv)
|
newVal = LeftRotate(sv)
|
||||||
fmt.Println("21")
|
|
||||||
}
|
}
|
||||||
fmt.Println("22 end add")
|
*/
|
||||||
return newVal
|
return newVal
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -476,9 +447,6 @@ func RightRotate(y *Node) *Node {
|
|||||||
// Perform rotation
|
// Perform rotation
|
||||||
x.right = y
|
x.right = y
|
||||||
y.left = t2
|
y.left = t2
|
||||||
fmt.Println("RightRotate: return=" + x.value + "; L:" + x.left.value + "; R:" + x.right.value)
|
|
||||||
fmt.Println("RightRotate: leftNode=" + x.getLeftValue() + "; L:" + x.left.getLeftValue() + "; R:" + x.left.getRightValue())
|
|
||||||
fmt.Println("RightRotate: rightNode=" + x.getRightValue() + "; L:" + x.right.getLeftValue() + "; R:" + x.right.getRightValue())
|
|
||||||
// Return new root
|
// Return new root
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
@ -490,9 +458,6 @@ func LeftRotate(x *Node) *Node {
|
|||||||
y.left = x
|
y.left = x
|
||||||
x.right = t2
|
x.right = t2
|
||||||
// Return new root
|
// Return new root
|
||||||
fmt.Println("LeftRotate: return=" + y.value + "; L:" + y.left.value + "; R:" + y.right.value)
|
|
||||||
fmt.Println("LeftRotate: leftNode=" + y.getLeftValue() + "; L:" + y.left.getLeftValue() + "; R:" + y.left.getRightValue())
|
|
||||||
fmt.Println("LeftRotate: rightNode=" + y.getRightValue() + "; L:" + y.right.getLeftValue() + "; R:" + y.right.getRightValue())
|
|
||||||
return y
|
return y
|
||||||
}
|
}
|
||||||
|
|
||||||
|
58
go/hello-world/README.md
Normal file
58
go/hello-world/README.md
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
# Hello World
|
||||||
|
|
||||||
|
Write a function that greets the user by name, or by saying "Hello, World!" if no name is given.
|
||||||
|
|
||||||
|
["Hello, World!"](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) is the traditional first program for beginning programming in a new language.
|
||||||
|
|
||||||
|
**Note:** You can skip this exercise by running:
|
||||||
|
|
||||||
|
exercism skip $LANGUAGE hello-world
|
||||||
|
|
||||||
|
## Specification
|
||||||
|
|
||||||
|
Write a `Hello World!` function that can greet someone given their name.
|
||||||
|
The function should return the appropriate greeting.
|
||||||
|
|
||||||
|
For an input of "Alice", the response should be "Hello, Alice!".
|
||||||
|
|
||||||
|
If a name is not given, the response should be "Hello, World!"
|
||||||
|
|
||||||
|
## Test-Driven Development
|
||||||
|
|
||||||
|
As programmers mature, they eventually want to test their code.
|
||||||
|
|
||||||
|
Here at Exercism we simulate [Test-Driven Development](http://en.wikipedia.org/wiki/Test-driven_development) (TDD), where you write your tests before writing any functionality. The simulation comes in the form of a pre-written test suite, which will signal that you have solved the problem.
|
||||||
|
|
||||||
|
It will also provide you with a safety net to explore other solutions without breaking the functionality.
|
||||||
|
|
||||||
|
### A typical TDD workflow on Exercism:
|
||||||
|
|
||||||
|
1. Run the test file and pick one test that's failing.
|
||||||
|
2. Write some code to fix the test you picked.
|
||||||
|
3. Re-run the tests to confirm the test is now passing.
|
||||||
|
4. Repeat from step 1.
|
||||||
|
5. Submit your solution (`exercism submit /path/to/file`)
|
||||||
|
|
||||||
|
## Instructions
|
||||||
|
|
||||||
|
Submissions are encouraged to be general, within reason. Having said that, it's also important not to over-engineer a solution.
|
||||||
|
|
||||||
|
It's important to remember that the goal is to make code as expressive and readable as we can. However, solutions to the hello-world exercise will not be reviewed by a person, but by rikki- the robot, who will offer an encouraging word.
|
||||||
|
|
||||||
|
To run the tests simply run the command `go test` in the exercise directory.
|
||||||
|
|
||||||
|
If the test suite contains benchmarks, you can run these with the `-bench`
|
||||||
|
flag:
|
||||||
|
|
||||||
|
go test -bench .
|
||||||
|
|
||||||
|
For more detailed info about the Go track see the [help
|
||||||
|
page](http://exercism.io/languages/go).
|
||||||
|
|
||||||
|
## Source
|
||||||
|
|
||||||
|
This is an exercise to introduce users to using Exercism [http://en.wikipedia.org/wiki/%22Hello,_world!%22_program](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program)
|
||||||
|
|
||||||
|
## Submitting Incomplete Problems
|
||||||
|
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
||||||
|
|
29
go/hello-world/hello_test.go
Normal file
29
go/hello-world/hello_test.go
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package hello
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
// Define a function HelloWorld(string) string.
|
||||||
|
//
|
||||||
|
// Also define a testVersion with a value that matches
|
||||||
|
// the targetTestVersion here.
|
||||||
|
|
||||||
|
const targetTestVersion = 2
|
||||||
|
|
||||||
|
func TestHelloWorld(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name, expected string
|
||||||
|
}{
|
||||||
|
{"", "Hello, World!"},
|
||||||
|
{"Gopher", "Hello, Gopher!"},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
observed := HelloWorld(test.name)
|
||||||
|
if observed != test.expected {
|
||||||
|
t.Fatalf("HelloWorld(%s) = %v, want %v", test.name, observed, test.expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if testVersion != targetTestVersion {
|
||||||
|
t.Fatalf("Found testVersion = %v, want %v", testVersion, targetTestVersion)
|
||||||
|
}
|
||||||
|
}
|
11
go/hello-world/hello_world.go
Normal file
11
go/hello-world/hello_world.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package hello
|
||||||
|
|
||||||
|
const testVersion = 2
|
||||||
|
|
||||||
|
// HelloWorld takes a string (optionally empty) and says hello to it!
|
||||||
|
func HelloWorld(s string) string {
|
||||||
|
if s == "" {
|
||||||
|
s = "World"
|
||||||
|
}
|
||||||
|
return "Hello, " + s + "!"
|
||||||
|
}
|
38
go/phone-number/README.md
Normal file
38
go/phone-number/README.md
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
# Phone Number
|
||||||
|
|
||||||
|
Write a program that cleans up user-entered phone numbers so that they can be sent SMS messages.
|
||||||
|
|
||||||
|
The rules are as follows:
|
||||||
|
|
||||||
|
- If the phone number is less than 10 digits assume that it is bad
|
||||||
|
number
|
||||||
|
- If the phone number is 10 digits assume that it is good
|
||||||
|
- If the phone number is 11 digits and the first number is 1, trim the 1
|
||||||
|
and use the last 10 digits
|
||||||
|
- If the phone number is 11 digits and the first number is not 1, then
|
||||||
|
it is a bad number
|
||||||
|
- If the phone number is more than 11 digits assume that it is a bad
|
||||||
|
number
|
||||||
|
|
||||||
|
We've provided tests, now make them pass.
|
||||||
|
|
||||||
|
Hint: Only make one test pass at a time. Disable the others, then flip
|
||||||
|
each on in turn after you get the current failing one to pass.
|
||||||
|
|
||||||
|
To run the tests simply run the command `go test` in the exercise directory.
|
||||||
|
|
||||||
|
If the test suite contains benchmarks, you can run these with the `-bench`
|
||||||
|
flag:
|
||||||
|
|
||||||
|
go test -bench .
|
||||||
|
|
||||||
|
For more detailed info about the Go track see the [help
|
||||||
|
page](http://exercism.io/languages/go).
|
||||||
|
|
||||||
|
## Source
|
||||||
|
|
||||||
|
Event Manager by JumpstartLab [http://tutorials.jumpstartlab.com/projects/eventmanager.html](http://tutorials.jumpstartlab.com/projects/eventmanager.html)
|
||||||
|
|
||||||
|
## Submitting Incomplete Problems
|
||||||
|
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
||||||
|
|
118
go/phone-number/phone_number_test.go
Normal file
118
go/phone-number/phone_number_test.go
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
package phonenumber
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type testCase struct {
|
||||||
|
input string
|
||||||
|
expected string
|
||||||
|
expectErr bool
|
||||||
|
}
|
||||||
|
|
||||||
|
var numberTests = []testCase{
|
||||||
|
{"(123) 456-7890", "1234567890", false},
|
||||||
|
{"123.456.7890", "1234567890", false},
|
||||||
|
{"1234567890", "1234567890", false},
|
||||||
|
{"12345678901234567", "", true},
|
||||||
|
{"21234567890", "", true},
|
||||||
|
{"123456789", "", true},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNumber(t *testing.T) {
|
||||||
|
for _, test := range numberTests {
|
||||||
|
actual, actualErr := Number(test.input)
|
||||||
|
if actual != test.expected {
|
||||||
|
t.Errorf("Number(%s): expected [%s], actual: [%s]", test.input, test.expected, actual)
|
||||||
|
}
|
||||||
|
// if we expect an error and there isn't one
|
||||||
|
if test.expectErr && actualErr == nil {
|
||||||
|
t.Errorf("Number(%s): expected an error, but error is nil", test.input)
|
||||||
|
}
|
||||||
|
// if we don't expect an error and there is one
|
||||||
|
if !test.expectErr && actualErr != nil {
|
||||||
|
t.Errorf("Number(%s): expected no error, but error is: %s", test.input, actualErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkNumber(b *testing.B) {
|
||||||
|
b.StopTimer()
|
||||||
|
for _, test := range numberTests {
|
||||||
|
b.StartTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
Number(test.input)
|
||||||
|
}
|
||||||
|
b.StopTimer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var areaCodeTests = []testCase{
|
||||||
|
{"1234567890", "123", false},
|
||||||
|
{"213.456.7890", "213", false},
|
||||||
|
{"213.456.7890.2345", "", true},
|
||||||
|
{"213.456", "", true},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAreaCode(t *testing.T) {
|
||||||
|
for _, test := range areaCodeTests {
|
||||||
|
actual, actualErr := AreaCode(test.input)
|
||||||
|
if actual != test.expected {
|
||||||
|
t.Errorf("AreaCode(%s): expected [%s], actual: [%s]", test.input, test.expected, actual)
|
||||||
|
}
|
||||||
|
// if we expect an error and there isn't one
|
||||||
|
if test.expectErr && actualErr == nil {
|
||||||
|
t.Errorf("AreaCode(%s): expected an error, but error is nil", test.input)
|
||||||
|
}
|
||||||
|
// if we don't expect an error and there is one
|
||||||
|
if !test.expectErr && actualErr != nil {
|
||||||
|
t.Errorf("AreaCode(%s): expected no error, but error is: %s", test.input, actualErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkAreaCode(b *testing.B) {
|
||||||
|
b.StopTimer()
|
||||||
|
for _, test := range areaCodeTests {
|
||||||
|
b.StartTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
AreaCode(test.input)
|
||||||
|
}
|
||||||
|
b.StopTimer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var formatTests = []testCase{
|
||||||
|
{"1234567890", "(123) 456-7890", false},
|
||||||
|
{"11234567890", "(123) 456-7890", false},
|
||||||
|
{"112345", "", true},
|
||||||
|
{"11234590870986", "", true},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFormat(t *testing.T) {
|
||||||
|
for _, test := range formatTests {
|
||||||
|
actual, actualErr := Format(test.input)
|
||||||
|
if actual != test.expected {
|
||||||
|
t.Errorf("Format(%s): expected [%s], actual: [%s]", test.input, test.expected, actual)
|
||||||
|
}
|
||||||
|
// if we expect an error and there isn't one
|
||||||
|
if test.expectErr && actualErr == nil {
|
||||||
|
t.Errorf("Format(%s): expected an error, but error is nil", test.input)
|
||||||
|
}
|
||||||
|
// if we don't expect an error and there is one
|
||||||
|
if !test.expectErr && actualErr != nil {
|
||||||
|
t.Errorf("Format(%s): expected no error, but error is: %s", test.input, actualErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkFormat(b *testing.B) {
|
||||||
|
b.StopTimer()
|
||||||
|
for _, test := range areaCodeTests {
|
||||||
|
b.StartTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
Format(test.input)
|
||||||
|
}
|
||||||
|
b.StopTimer()
|
||||||
|
}
|
||||||
|
}
|
44
go/phone-number/phonenumber.go
Normal file
44
go/phone-number/phonenumber.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package phonenumber
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Number takes a number and validates it
|
||||||
|
func Number(num string) (string, error) {
|
||||||
|
num = strings.Map(func(r rune) rune {
|
||||||
|
if r >= '0' && r <= '9' {
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}, num)
|
||||||
|
// A number can be 11 digits long, if it starts with a 1
|
||||||
|
// but ignore that one.
|
||||||
|
if len(num) == 11 && num[0] == '1' {
|
||||||
|
num = num[1:]
|
||||||
|
}
|
||||||
|
if len(num) != 10 {
|
||||||
|
return "", errors.New("Invalid Number")
|
||||||
|
}
|
||||||
|
return num, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AreaCode takes a number, validates it, and returns the area code
|
||||||
|
func AreaCode(num string) (string, error) {
|
||||||
|
num, err := Number(num)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return num[:3], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format takes a number, validates it and returns it in the format
|
||||||
|
// (nnn) nnn-nnnn
|
||||||
|
func Format(num string) (string, error) {
|
||||||
|
num, err := Number(num)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return "(" + num[:3] + ") " + num[3:6] + "-" + num[6:], nil
|
||||||
|
}
|
36
go/pig-latin/README.md
Normal file
36
go/pig-latin/README.md
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
# Pig Latin
|
||||||
|
|
||||||
|
Implement a program that translates from English to Pig Latin
|
||||||
|
|
||||||
|
Pig Latin is a made-up children's language that's intended to be
|
||||||
|
confusing. It obeys a few simple rules (below), but when it's spoken
|
||||||
|
quickly it's really difficult for non-children (and non-native speakers)
|
||||||
|
to understand.
|
||||||
|
|
||||||
|
- **Rule 1**: If a word begins with a vowel sound, add an "ay" sound to
|
||||||
|
the end of the word.
|
||||||
|
- **Rule 2**: If a word begins with a consonant sound, move it to the
|
||||||
|
end of the word, and then add an "ay" sound to the end of the word.
|
||||||
|
|
||||||
|
There are a few more rules for edge cases, and there are regional
|
||||||
|
variants too.
|
||||||
|
|
||||||
|
See <http://en.wikipedia.org/wiki/Pig_latin> for more details.
|
||||||
|
|
||||||
|
To run the tests simply run the command `go test` in the exercise directory.
|
||||||
|
|
||||||
|
If the test suite contains benchmarks, you can run these with the `-bench`
|
||||||
|
flag:
|
||||||
|
|
||||||
|
go test -bench .
|
||||||
|
|
||||||
|
For more detailed info about the Go track see the [help
|
||||||
|
page](http://exercism.io/languages/go).
|
||||||
|
|
||||||
|
## Source
|
||||||
|
|
||||||
|
The Pig Latin exercise at Test First Teaching by Ultrasaurus [https://github.com/ultrasaurus/test-first-teaching/blob/master/learn_ruby/pig_latin/](https://github.com/ultrasaurus/test-first-teaching/blob/master/learn_ruby/pig_latin/)
|
||||||
|
|
||||||
|
## Submitting Incomplete Problems
|
||||||
|
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
||||||
|
|
41
go/pig-latin/igpay.go
Normal file
41
go/pig-latin/igpay.go
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package igpay
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
// PigLatin takes some words and converts them to pig latin
|
||||||
|
// 1) Move starting consonant sounds to the end of the word
|
||||||
|
// 2) add 'ay'
|
||||||
|
func PigLatin(in string) string {
|
||||||
|
var ret string
|
||||||
|
words := strings.Split(in, " ")
|
||||||
|
for i := range words {
|
||||||
|
ret += pigLatinWord(words[i])
|
||||||
|
if i < len(words)-1 {
|
||||||
|
ret += " "
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// pigLatinWord actually does the heavy lifting
|
||||||
|
func pigLatinWord(in string) string {
|
||||||
|
var ret string
|
||||||
|
// First move all consonant sounds to the end
|
||||||
|
for i := 0; i < len(in); i++ {
|
||||||
|
// Edge consonant sound cases
|
||||||
|
if in[0] == 'q' && in[1] == 'u' {
|
||||||
|
in = in[2:] + string(in[0]) + string(in[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
vowelPos := strings.IndexAny(in, "aeiou")
|
||||||
|
|
||||||
|
// If we have a y and another vowel, then y is a consonant
|
||||||
|
// also, x
|
||||||
|
if vowelPos == 0 || (vowelPos > 1 && (in[0] == 'y' || in[0] == 'x')) {
|
||||||
|
return in + "ay"
|
||||||
|
}
|
||||||
|
in = in[1:] + string(in[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
29
go/pig-latin/pig_latin_test.go
Normal file
29
go/pig-latin/pig_latin_test.go
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package igpay
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
var tests = []struct{ pl, in string }{
|
||||||
|
{"appleay", "apple"},
|
||||||
|
{"earay", "ear"},
|
||||||
|
{"igpay", "pig"},
|
||||||
|
{"oalakay", "koala"},
|
||||||
|
{"airchay", "chair"},
|
||||||
|
{"eenquay", "queen"},
|
||||||
|
{"aresquay", "square"},
|
||||||
|
{"erapythay", "therapy"},
|
||||||
|
{"ushthray", "thrush"},
|
||||||
|
{"oolschay", "school"},
|
||||||
|
{"ickquay astfay unray", "quick fast run"},
|
||||||
|
{"ellowyay", "yellow"},
|
||||||
|
{"yttriaay", "yttria"},
|
||||||
|
{"enonxay", "xenon"},
|
||||||
|
{"xrayay", "xray"},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPigLatin(t *testing.T) {
|
||||||
|
for _, test := range tests {
|
||||||
|
if pl := PigLatin(test.in); pl != test.pl {
|
||||||
|
t.Fatalf("PigLatin(%q) = %q, want %q.", test.in, pl, test.pl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
48
go/prime-factors/README.md
Normal file
48
go/prime-factors/README.md
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
# Prime Factors
|
||||||
|
|
||||||
|
Compute the prime factors of a given natural number.
|
||||||
|
|
||||||
|
A prime number is only evenly divisible by itself and 1.
|
||||||
|
|
||||||
|
Note that 1 is not a prime number.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
What are the prime factors of 60?
|
||||||
|
|
||||||
|
- Our first divisor is 2. 2 goes into 60, leaving 30.
|
||||||
|
- 2 goes into 30, leaving 15.
|
||||||
|
- 2 doesn't go cleanly into 15. So let's move on to our next divisor, 3.
|
||||||
|
- 3 goes cleanly into 15, leaving 5.
|
||||||
|
- 3 does not go cleanly into 5. The next possible factor is 4.
|
||||||
|
- 4 does not go cleanly into 5. The next possible factor is 5.
|
||||||
|
- 5 does go cleanly into 5.
|
||||||
|
- We're left only with 1, so now, we're done.
|
||||||
|
|
||||||
|
Our successful divisors in that computation represent the list of prime
|
||||||
|
factors of 60: 2, 2, 3, and 5.
|
||||||
|
|
||||||
|
You can check this yourself:
|
||||||
|
|
||||||
|
- 2 * 2 * 3 * 5
|
||||||
|
- = 4 * 15
|
||||||
|
- = 60
|
||||||
|
- Success!
|
||||||
|
|
||||||
|
To run the tests simply run the command `go test` in the exercise directory.
|
||||||
|
|
||||||
|
If the test suite contains benchmarks, you can run these with the `-bench`
|
||||||
|
flag:
|
||||||
|
|
||||||
|
go test -bench .
|
||||||
|
|
||||||
|
For more detailed info about the Go track see the [help
|
||||||
|
page](http://exercism.io/languages/go).
|
||||||
|
|
||||||
|
## Source
|
||||||
|
|
||||||
|
The Prime Factors Kata by Uncle Bob [http://butunclebob.com/ArticleS.UncleBob.ThePrimeFactorsKata](http://butunclebob.com/ArticleS.UncleBob.ThePrimeFactorsKata)
|
||||||
|
|
||||||
|
## Submitting Incomplete Problems
|
||||||
|
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
||||||
|
|
21
go/prime-factors/prime.go
Normal file
21
go/prime-factors/prime.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package prime
|
||||||
|
|
||||||
|
const testVersion = 2
|
||||||
|
|
||||||
|
func Factors(fnd int64) []int64 {
|
||||||
|
var ret []int64
|
||||||
|
var i int64
|
||||||
|
foundFactor := true
|
||||||
|
for i = 2; i < fnd; i++ {
|
||||||
|
for j := range ret {
|
||||||
|
if i%ret[j] == 0 {
|
||||||
|
// Already covered this case, move on
|
||||||
|
foundFactor = false
|
||||||
|
}
|
||||||
|
if !foundFactor {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
48
go/prime-factors/primefactors_test.go
Normal file
48
go/prime-factors/primefactors_test.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package prime
|
||||||
|
|
||||||
|
// Return prime factors in increasing order
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
const targetTestVersion = 2
|
||||||
|
|
||||||
|
var tests = []struct {
|
||||||
|
input int64
|
||||||
|
expected []int64
|
||||||
|
}{
|
||||||
|
{1, []int64{}},
|
||||||
|
{2, []int64{2}},
|
||||||
|
{3, []int64{3}},
|
||||||
|
{4, []int64{2, 2}},
|
||||||
|
{6, []int64{2, 3}},
|
||||||
|
{8, []int64{2, 2, 2}},
|
||||||
|
{9, []int64{3, 3}},
|
||||||
|
{27, []int64{3, 3, 3}},
|
||||||
|
{625, []int64{5, 5, 5, 5}},
|
||||||
|
{901255, []int64{5, 17, 23, 461}},
|
||||||
|
{93819012551, []int64{11, 9539, 894119}},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPrimeFactors(t *testing.T) {
|
||||||
|
if testVersion != targetTestVersion {
|
||||||
|
t.Fatalf("Found testVersion = %v, want %v", testVersion, targetTestVersion)
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
actual := Factors(test.input)
|
||||||
|
if !reflect.DeepEqual(actual, test.expected) {
|
||||||
|
t.Errorf("prime.Factors(%d) = %v; expected %v",
|
||||||
|
test.input, actual, test.expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkPrimeFactors(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
for _, test := range tests {
|
||||||
|
Factors(test.input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
53
go/strain/README.md
Normal file
53
go/strain/README.md
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
# Strain
|
||||||
|
|
||||||
|
Implement the `keep` and `discard` operation on collections. Given a collection and a predicate on the collection's elements, `keep` returns a new collection containing those elements where the predicate is true, while `discard` returns a new collection containing those elements where the predicate is false.
|
||||||
|
|
||||||
|
Write two functions that each take a function and a list. One of them will
|
||||||
|
return the list of items for which the passed in function is true, and the
|
||||||
|
other will return the items for which it is false.
|
||||||
|
|
||||||
|
For example, given the collection of numbers:
|
||||||
|
|
||||||
|
- 1, 2, 3, 4, 5
|
||||||
|
|
||||||
|
And the predicate:
|
||||||
|
|
||||||
|
- is the number even?
|
||||||
|
|
||||||
|
Then your keep operation should produce:
|
||||||
|
|
||||||
|
- 2, 4
|
||||||
|
|
||||||
|
While your discard operation should produce:
|
||||||
|
|
||||||
|
- 1, 3, 5
|
||||||
|
|
||||||
|
Note that the union of keep and discard is all the elements.
|
||||||
|
|
||||||
|
The functions may be called `keep` and `discard`, or they may need different
|
||||||
|
names in order to not clash with existing functions or concepts in your
|
||||||
|
language.
|
||||||
|
|
||||||
|
## Restrictions
|
||||||
|
|
||||||
|
Keep your hands off that filter/reject/whatchamacallit functionality
|
||||||
|
provided by your standard library! Solve this one yourself using other
|
||||||
|
basic tools instead.
|
||||||
|
|
||||||
|
To run the tests simply run the command `go test` in the exercise directory.
|
||||||
|
|
||||||
|
If the test suite contains benchmarks, you can run these with the `-bench`
|
||||||
|
flag:
|
||||||
|
|
||||||
|
go test -bench .
|
||||||
|
|
||||||
|
For more detailed info about the Go track see the [help
|
||||||
|
page](http://exercism.io/languages/go).
|
||||||
|
|
||||||
|
## Source
|
||||||
|
|
||||||
|
Conversation with James Edward Gray II [https://twitter.com/jeg2](https://twitter.com/jeg2)
|
||||||
|
|
||||||
|
## Submitting Incomplete Problems
|
||||||
|
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
||||||
|
|
54
go/strain/strain.go
Normal file
54
go/strain/strain.go
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
package strain
|
||||||
|
|
||||||
|
// Ints is a slice of int
|
||||||
|
type Ints []int
|
||||||
|
|
||||||
|
// Lists is a slice of int slices
|
||||||
|
type Lists [][]int
|
||||||
|
|
||||||
|
// Strings is a slice of strings
|
||||||
|
type Strings []string
|
||||||
|
|
||||||
|
// Keep runs the Ints through a function and returns the ones that succeed
|
||||||
|
func (i Ints) Keep(kf func(int) bool) Ints {
|
||||||
|
var ret Ints
|
||||||
|
for idx := range i {
|
||||||
|
if kf(i[idx]) {
|
||||||
|
ret = append(ret, i[idx])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// Discard runs the Ints through a function and returns the ones that fail
|
||||||
|
func (i Ints) Discard(df func(int) bool) Ints {
|
||||||
|
var ret Ints
|
||||||
|
for idx := range i {
|
||||||
|
if !df(i[idx]) {
|
||||||
|
ret = append(ret, i[idx])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep runs the Lists through a function and returns the ones that succeed
|
||||||
|
func (l Lists) Keep(kf func([]int) bool) Lists {
|
||||||
|
var ret Lists
|
||||||
|
for idx := range l {
|
||||||
|
if kf(l[idx]) {
|
||||||
|
ret = append(ret, l[idx])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep runs the Strings through a function and returns the ones that succeed
|
||||||
|
func (s Strings) Keep(kf func(string) bool) Strings {
|
||||||
|
var ret Strings
|
||||||
|
for idx := range s {
|
||||||
|
if kf(s[idx]) {
|
||||||
|
ret = append(ret, s[idx])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
170
go/strain/strain_test.go
Normal file
170
go/strain/strain_test.go
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
// Collections, hm? For this exercise in Go you'll work with slices as
|
||||||
|
// collections. Define the following in your solution:
|
||||||
|
//
|
||||||
|
// type Ints []int
|
||||||
|
// type Lists [][]int
|
||||||
|
// type Strings []string
|
||||||
|
//
|
||||||
|
// Then complete the exercise by implementing these methods:
|
||||||
|
//
|
||||||
|
// (Ints) Keep(func(int) bool) Ints
|
||||||
|
// (Ints) Discard(func(int) bool) Ints
|
||||||
|
// (Lists) Keep(func([]int) bool) Lists
|
||||||
|
// (Strings) Keep(func(string) bool) Strings
|
||||||
|
|
||||||
|
package strain
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func lt10(x int) bool { return x < 10 }
|
||||||
|
func gt10(x int) bool { return x > 10 }
|
||||||
|
func odd(x int) bool { return x&1 == 1 }
|
||||||
|
func even(x int) bool { return x&1 == 0 }
|
||||||
|
|
||||||
|
var keepTests = []struct {
|
||||||
|
pred func(int) bool
|
||||||
|
list Ints
|
||||||
|
want Ints
|
||||||
|
}{
|
||||||
|
{lt10,
|
||||||
|
nil,
|
||||||
|
nil},
|
||||||
|
{lt10,
|
||||||
|
Ints{1, 2, 3},
|
||||||
|
Ints{1, 2, 3}},
|
||||||
|
{odd,
|
||||||
|
Ints{1, 2, 3},
|
||||||
|
Ints{1, 3}},
|
||||||
|
{even,
|
||||||
|
Ints{1, 2, 3, 4, 5},
|
||||||
|
Ints{2, 4}},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestKeepInts(t *testing.T) {
|
||||||
|
for _, test := range keepTests {
|
||||||
|
// setup here copies test.list, preserving the nil value if it is nil
|
||||||
|
// and making a fresh copy of the underlying array otherwise.
|
||||||
|
cp := test.list
|
||||||
|
if cp != nil {
|
||||||
|
cp = append(Ints{}, cp...)
|
||||||
|
}
|
||||||
|
switch res := cp.Keep(test.pred); {
|
||||||
|
case !reflect.DeepEqual(cp, test.list):
|
||||||
|
t.Fatalf("Ints%v.Keep() should not modify its reciever. "+
|
||||||
|
"Found %v, reciever should stay %v",
|
||||||
|
test.list, cp, test.list)
|
||||||
|
case !reflect.DeepEqual(res, test.want):
|
||||||
|
t.Fatalf("Ints%v.Keep() = %v, want %v",
|
||||||
|
test.list, res, test.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var discardTests = []struct {
|
||||||
|
pred func(int) bool
|
||||||
|
list Ints
|
||||||
|
want Ints
|
||||||
|
}{
|
||||||
|
{lt10,
|
||||||
|
nil,
|
||||||
|
nil},
|
||||||
|
{gt10,
|
||||||
|
Ints{1, 2, 3},
|
||||||
|
Ints{1, 2, 3}},
|
||||||
|
{odd,
|
||||||
|
Ints{1, 2, 3},
|
||||||
|
Ints{2}},
|
||||||
|
{even,
|
||||||
|
Ints{1, 2, 3, 4, 5},
|
||||||
|
Ints{1, 3, 5}},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDiscardInts(t *testing.T) {
|
||||||
|
for _, test := range discardTests {
|
||||||
|
cp := test.list
|
||||||
|
if cp != nil {
|
||||||
|
cp = append(Ints{}, cp...) // dup underlying array
|
||||||
|
}
|
||||||
|
switch res := cp.Discard(test.pred); {
|
||||||
|
case !reflect.DeepEqual(cp, test.list):
|
||||||
|
t.Fatalf("Ints%v.Discard() should not modify its reciever. "+
|
||||||
|
"Found %v, reciever should stay %v",
|
||||||
|
test.list, cp, test.list)
|
||||||
|
case !reflect.DeepEqual(res, test.want):
|
||||||
|
t.Fatalf("Ints%v.Discard() = %v, want %v",
|
||||||
|
test.list, res, test.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestKeepStrings(t *testing.T) {
|
||||||
|
zword := func(s string) bool { return len(s) > 0 && s[0] == 'z' }
|
||||||
|
list := Strings{"apple", "zebra", "banana", "zombies", "cherimoya", "zelot"}
|
||||||
|
want := Strings{"zebra", "zombies", "zelot"}
|
||||||
|
|
||||||
|
cp := append(Strings{}, list...) // make copy, as with TestInts
|
||||||
|
switch res := cp.Keep(zword); {
|
||||||
|
case !reflect.DeepEqual(cp, list):
|
||||||
|
t.Fatalf("Strings%v.Keep() should not modify its reciever. "+
|
||||||
|
"Found %v, reciever should stay %v",
|
||||||
|
list, cp, list)
|
||||||
|
case !reflect.DeepEqual(res, want):
|
||||||
|
t.Fatalf("Strings%v.Keep() = %v, want %v",
|
||||||
|
list, res, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestKeepLists(t *testing.T) {
|
||||||
|
has5 := func(l []int) bool {
|
||||||
|
for _, e := range l {
|
||||||
|
if e == 5 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
list := Lists{
|
||||||
|
{1, 2, 3},
|
||||||
|
{5, 5, 5},
|
||||||
|
{5, 1, 2},
|
||||||
|
{2, 1, 2},
|
||||||
|
{1, 5, 2},
|
||||||
|
{2, 2, 1},
|
||||||
|
{1, 2, 5},
|
||||||
|
}
|
||||||
|
want := Lists{
|
||||||
|
{5, 5, 5},
|
||||||
|
{5, 1, 2},
|
||||||
|
{1, 5, 2},
|
||||||
|
{1, 2, 5},
|
||||||
|
}
|
||||||
|
cp := append(Lists{}, list...)
|
||||||
|
switch res := cp.Keep(has5); {
|
||||||
|
case !reflect.DeepEqual(cp, list):
|
||||||
|
t.Fatalf("Lists%v.Keep() should not modify its reciever. "+
|
||||||
|
"Found %v, reciever should stay %v",
|
||||||
|
list, cp, list)
|
||||||
|
case !reflect.DeepEqual(res, want):
|
||||||
|
t.Fatalf("Lists%v.Keep() = %v, want %v",
|
||||||
|
list, res, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkKeepInts(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
for _, test := range keepTests {
|
||||||
|
test.list.Keep(test.pred)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkDiscardInts(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
for _, test := range discardTests {
|
||||||
|
test.list.Discard(test.pred)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user