Merge Go Work
This commit is contained in:
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)
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user