mirror of
https://github.com/golang/go
synced 2024-11-18 10:54:40 -07:00
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
This commit is contained in:
parent
b8035ab5a5
commit
03fbd72ddb
@ -10,15 +10,17 @@ package iterable
|
||||
|
||||
import "vector"
|
||||
|
||||
|
||||
type Iterable interface {
|
||||
// Iter should return a fresh channel each time it is called.
|
||||
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.
|
||||
func All(iter Iterable, f func(e interface {}) bool) bool {
|
||||
func All(iter Iterable, f func(interface {}) bool) bool {
|
||||
for e := range iter.Iter() {
|
||||
if !f(e) {
|
||||
return false
|
||||
@ -27,13 +29,11 @@ func All(iter Iterable, f func(e interface {}) bool) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
// Any tests whether f is true for at least one element of iter.
|
||||
func Any(iter Iterable, f func(e interface {}) bool) bool {
|
||||
return !All(iter, func(e interface {}) bool { return !f(e) });
|
||||
func Any(iter Iterable, f func(interface {}) bool) bool {
|
||||
return !All(iter, not(f))
|
||||
}
|
||||
|
||||
|
||||
// Data returns a slice containing the elements of iter.
|
||||
func Data(iter Iterable) []interface {} {
|
||||
vec := vector.New(0);
|
||||
@ -43,6 +43,41 @@ func Data(iter Iterable) []interface {} {
|
||||
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.
|
||||
type mappedIterable struct {
|
||||
@ -50,31 +85,30 @@ type mappedIterable struct {
|
||||
f func(interface {}) interface {};
|
||||
}
|
||||
|
||||
|
||||
func (m mappedIterable) iterate(out chan<- interface {}) {
|
||||
func (m *mappedIterable) iterate(out chan<- interface {}) {
|
||||
for e := range m.it.Iter() {
|
||||
out <- m.f(e)
|
||||
}
|
||||
close(out)
|
||||
}
|
||||
|
||||
|
||||
func (m mappedIterable) Iter() <-chan interface {} {
|
||||
func (m *mappedIterable) Iter() <-chan interface {} {
|
||||
ch := make(chan interface {});
|
||||
go m.iterate(ch);
|
||||
return ch;
|
||||
}
|
||||
|
||||
|
||||
// Map returns an Iterable that returns the result of applying f to each
|
||||
// element of iter.
|
||||
func Map(iter Iterable, f func(e interface {}) interface {}) Iterable {
|
||||
return mappedIterable{ iter, f }
|
||||
func Map(iter Iterable, f func(interface {}) interface {}) Iterable {
|
||||
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:
|
||||
// - Find, Filter
|
||||
// - Inject
|
||||
// - Partition
|
||||
// - Zip
|
||||
|
@ -43,6 +43,17 @@ func addOne(n interface {}) interface {} {
|
||||
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) {
|
||||
if !All(oneToFive, isPositive) {
|
||||
@ -53,7 +64,6 @@ func TestAll(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func TestAny(t *testing.T) {
|
||||
if Any(oneToFive, isNegative) {
|
||||
t.Error("Any(oneToFive, isNegative) == true")
|
||||
@ -63,16 +73,47 @@ func TestAny(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func assertArraysAreEqual(t *testing.T, res []interface {}, expected []int) {
|
||||
if len(res) != len(expected) {
|
||||
t.Errorf("len(res) = %v, want %v", len(res), len(expected));
|
||||
goto missing
|
||||
}
|
||||
for i := range res {
|
||||
if v := res[i].(int); v != 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));
|
||||
if len(res) != len(oneToFive) {
|
||||
t.Fatal("len(res) = %v, want %v", len(res), len(oneToFive))
|
||||
}
|
||||
expected := []int{ 3, 5, 7, 9, 11 };
|
||||
for i := range res {
|
||||
if res[i].(int) != expected[i] {
|
||||
t.Errorf("res[%v] = %v, want %v", i, res[i], expected[i])
|
||||
}
|
||||
}
|
||||
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 })
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user