Commit 03fbd72d authored by David Symonds's avatar David Symonds

Add new functions to the iterable package:

- Filter
- Find
- Partition

R=rsc
APPROVED=rsc
DELTA=117  (92 added, 17 deleted, 8 changed)
OCL=27135
CL=27240
parent b8035ab5
...@@ -10,15 +10,17 @@ package iterable ...@@ -10,15 +10,17 @@ package iterable
import "vector" import "vector"
type Iterable interface { type Iterable interface {
// Iter should return a fresh channel each time it is called. // Iter should return a fresh channel each time it is called.
Iter() <-chan interface {} Iter() <-chan interface {}
} }
func not(f func(interface {}) bool) (func(interface {}) bool) {
return func(e interface {}) bool { return !f(e) }
}
// All tests whether f is true for every element of iter. // All tests whether f is true for every element of iter.
func All(iter Iterable, f func(e interface {}) bool) bool { func All(iter Iterable, f func(interface {}) bool) bool {
for e := range iter.Iter() { for e := range iter.Iter() {
if !f(e) { if !f(e) {
return false return false
...@@ -27,13 +29,11 @@ func All(iter Iterable, f func(e interface {}) bool) bool { ...@@ -27,13 +29,11 @@ func All(iter Iterable, f func(e interface {}) bool) bool {
return true return true
} }
// Any tests whether f is true for at least one element of iter. // Any tests whether f is true for at least one element of iter.
func Any(iter Iterable, f func(e interface {}) bool) bool { func Any(iter Iterable, f func(interface {}) bool) bool {
return !All(iter, func(e interface {}) bool { return !f(e) }); return !All(iter, not(f))
} }
// Data returns a slice containing the elements of iter. // Data returns a slice containing the elements of iter.
func Data(iter Iterable) []interface {} { func Data(iter Iterable) []interface {} {
vec := vector.New(0); vec := vector.New(0);
...@@ -43,6 +43,41 @@ func Data(iter Iterable) []interface {} { ...@@ -43,6 +43,41 @@ func Data(iter Iterable) []interface {} {
return vec.Data() return vec.Data()
} }
// filteredIterable is a struct that implements Iterable with each element
// passed through a filter.
type filteredIterable struct {
it Iterable;
f func(interface {}) bool;
}
func (f *filteredIterable) iterate(out chan<- interface {}) {
for e := range f.it.Iter() {
if f.f(e) {
out <- e
}
}
close(out)
}
func (f *filteredIterable) Iter() <-chan interface {} {
ch := make(chan interface {});
go f.iterate(ch);
return ch;
}
// Filter returns an Iterable that returns the elements of iter that satisfy f.
func Filter(iter Iterable, f func(interface {}) bool) Iterable {
return &filteredIterable{ iter, f }
}
// Find returns the first element of iter that satisfies f.
// Returns nil if no such element is found.
func Find(iter Iterable, f func(interface {}) bool) interface {} {
for e := range Filter(iter, f).Iter() {
return e
}
return nil
}
// mappedIterable is a helper struct that implements Iterable, returned by Map. // mappedIterable is a helper struct that implements Iterable, returned by Map.
type mappedIterable struct { type mappedIterable struct {
...@@ -50,31 +85,30 @@ type mappedIterable struct { ...@@ -50,31 +85,30 @@ type mappedIterable struct {
f func(interface {}) interface {}; f func(interface {}) interface {};
} }
func (m *mappedIterable) iterate(out chan<- interface {}) {
func (m mappedIterable) iterate(out chan<- interface {}) {
for e := range m.it.Iter() { for e := range m.it.Iter() {
out <- m.f(e) out <- m.f(e)
} }
close(out) close(out)
} }
func (m *mappedIterable) Iter() <-chan interface {} {
func (m mappedIterable) Iter() <-chan interface {} {
ch := make(chan interface {}); ch := make(chan interface {});
go m.iterate(ch); go m.iterate(ch);
return ch; return ch;
} }
// Map returns an Iterable that returns the result of applying f to each // Map returns an Iterable that returns the result of applying f to each
// element of iter. // element of iter.
func Map(iter Iterable, f func(e interface {}) interface {}) Iterable { func Map(iter Iterable, f func(interface {}) interface {}) Iterable {
return mappedIterable{ iter, f } return &mappedIterable{ iter, f }
} }
// Partition(iter, f) returns Filter(iter, f) and Filter(iter, !f).
func Partition(iter Iterable, f func(interface {}) bool) (Iterable, Iterable) {
return Filter(iter, f), Filter(iter, not(f))
}
// TODO: // TODO:
// - Find, Filter
// - Inject // - Inject
// - Partition
// - Zip // - Zip
...@@ -43,6 +43,17 @@ func addOne(n interface {}) interface {} { ...@@ -43,6 +43,17 @@ func addOne(n interface {}) interface {} {
return n.(int) + 1 return n.(int) + 1
} }
// A stream of the natural numbers: 0, 1, 2, 3, ...
type integerStream struct {}
func (i integerStream) Iter() <-chan interface {} {
ch := make(chan interface {});
go func() {
for i := 0; ; i++ {
ch <- i
}
}();
return ch
}
func TestAll(t *testing.T) { func TestAll(t *testing.T) {
if !All(oneToFive, isPositive) { if !All(oneToFive, isPositive) {
...@@ -53,7 +64,6 @@ func TestAll(t *testing.T) { ...@@ -53,7 +64,6 @@ func TestAll(t *testing.T) {
} }
} }
func TestAny(t *testing.T) { func TestAny(t *testing.T) {
if Any(oneToFive, isNegative) { if Any(oneToFive, isNegative) {
t.Error("Any(oneToFive, isNegative) == true") t.Error("Any(oneToFive, isNegative) == true")
...@@ -63,16 +73,47 @@ func TestAny(t *testing.T) { ...@@ -63,16 +73,47 @@ func TestAny(t *testing.T) {
} }
} }
func assertArraysAreEqual(t *testing.T, res []interface {}, expected []int) {
func TestMap(t *testing.T) { if len(res) != len(expected) {
res := Data(Map(Map(oneToFive, doubler), addOne)); t.Errorf("len(res) = %v, want %v", len(res), len(expected));
if len(res) != len(oneToFive) { goto missing
t.Fatal("len(res) = %v, want %v", len(res), len(oneToFive))
} }
expected := []int{ 3, 5, 7, 9, 11 };
for i := range res { for i := range res {
if res[i].(int) != expected[i] { if v := res[i].(int); v != expected[i] {
t.Errorf("res[%v] = %v, want %v", i, res[i], expected[i]) t.Errorf("res[%v] = %v, want %v", i, v, expected[i]);
goto missing
} }
} }
return;
missing:
t.Errorf("res = %v\nwant %v", res, expected);
}
func TestFilter(t *testing.T) {
ints := integerStream{};
moreInts := Filter(ints, isAbove3).Iter();
res := make([]interface {}, 3);
for i := 0; i < 3; i++ {
res[i] = <-moreInts;
}
assertArraysAreEqual(t, res, []int{ 4, 5, 6 })
}
func TestFind(t *testing.T) {
ints := integerStream{};
first := Find(ints, isAbove3);
if first.(int) != 4 {
t.Errorf("Find(ints, isAbove3) = %v, want 4", first)
}
}
func TestMap(t *testing.T) {
res := Data(Map(Map(oneToFive, doubler), addOne));
assertArraysAreEqual(t, res, []int{ 3, 5, 7, 9, 11 })
}
func TestPartition(t *testing.T) {
ti, fi := Partition(oneToFive, isEven);
assertArraysAreEqual(t, Data(ti), []int{ 2, 4 });
assertArraysAreEqual(t, Data(fi), []int{ 1, 3, 5 })
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment