171 lines
3.7 KiB
Go
171 lines
3.7 KiB
Go
// 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)
|
|
}
|
|
}
|
|
}
|