Merge pull request #9087 from ProofOfKeags/fn/list-filter
fn: add Filter to List
This commit is contained in:
2 files changed
+108
No files matched your search
+15
@@ -300,3 +300,18 @@ func (l *List[A]) PushFrontList(other *List[A]) {
|
|||||||
n = n.Prev()
|
n = n.Prev()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Filter gives a slice of all of the node values that satisfy the given
|
||||||
|
// predicate.
|
||||||
|
func (l *List[A]) Filter(f Pred[A]) []A {
|
||||||
|
var acc []A
|
||||||
|
|
||||||
|
for cursor := l.Front(); cursor != nil; cursor = cursor.Next() {
|
||||||
|
a := cursor.Value
|
||||||
|
if f(a) {
|
||||||
|
acc = append(acc, a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc
|
||||||
|
}
|
||||||
@@ -5,6 +5,9 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
"testing/quick"
|
"testing/quick"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"golang.org/x/exp/slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GenList(r *rand.Rand) *List[uint32] {
|
func GenList(r *rand.Rand) *List[uint32] {
|
||||||
@@ -727,3 +730,93 @@ func TestMoveUnknownMark(t *testing.T) {
|
|||||||
checkList(t, &l1, []int{1})
|
checkList(t, &l1, []int{1})
|
||||||
checkList(t, &l2, []int{2})
|
checkList(t, &l2, []int{2})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestFilterIdempotence ensures that the slice coming out of List.Filter is
|
||||||
|
// the same as that slice filtered again by the same predicate.
|
||||||
|
func TestFilterIdempotence(t *testing.T) {
|
||||||
|
require.NoError(
|
||||||
|
t, quick.Check(
|
||||||
|
func(l *List[uint32], modSize uint32) bool {
|
||||||
|
pred := func(a uint32) bool {
|
||||||
|
return a%modSize != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
filtered := l.Filter(pred)
|
||||||
|
|
||||||
|
filteredAgain := Filter(pred, filtered)
|
||||||
|
|
||||||
|
return slices.Equal(filtered, filteredAgain)
|
||||||
|
},
|
||||||
|
&quick.Config{
|
||||||
|
Values: func(vs []reflect.Value, r *rand.Rand) {
|
||||||
|
l := GenList(r)
|
||||||
|
vs[0] = reflect.ValueOf(l)
|
||||||
|
vs[1] = reflect.ValueOf(
|
||||||
|
r.Uint32()%5 + 1,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestFilterShrinks ensures that the length of the slice returned from
|
||||||
|
// List.Filter is never larger than the length of the List.
|
||||||
|
func TestFilterShrinks(t *testing.T) {
|
||||||
|
require.NoError(
|
||||||
|
t, quick.Check(
|
||||||
|
func(l *List[uint32], modSize uint32) bool {
|
||||||
|
pred := func(a uint32) bool {
|
||||||
|
return a%modSize != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
filteredSize := len(l.Filter(pred))
|
||||||
|
|
||||||
|
return filteredSize <= l.Len()
|
||||||
|
},
|
||||||
|
&quick.Config{
|
||||||
|
Values: func(vs []reflect.Value, r *rand.Rand) {
|
||||||
|
l := GenList(r)
|
||||||
|
vs[0] = reflect.ValueOf(l)
|
||||||
|
vs[1] = reflect.ValueOf(
|
||||||
|
r.Uint32()%5 + 1,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestFilterLawOfExcludedMiddle ensures that if we intersect a List.Filter
|
||||||
|
// with its negation that the intersection is the empty set.
|
||||||
|
func TestFilterLawOfExcludedMiddle(t *testing.T) {
|
||||||
|
require.NoError(
|
||||||
|
t, quick.Check(
|
||||||
|
func(l *List[uint32], modSize uint32) bool {
|
||||||
|
pred := func(a uint32) bool {
|
||||||
|
return a%modSize != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
negatedPred := func(a uint32) bool {
|
||||||
|
return !pred(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
positive := NewSet(l.Filter(pred)...)
|
||||||
|
negative := NewSet(l.Filter(negatedPred)...)
|
||||||
|
|
||||||
|
return positive.Intersect(negative).Equal(
|
||||||
|
NewSet[uint32](),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
&quick.Config{
|
||||||
|
Values: func(vs []reflect.Value, r *rand.Rand) {
|
||||||
|
l := GenList(r)
|
||||||
|
vs[0] = reflect.ValueOf(l)
|
||||||
|
vs[1] = reflect.ValueOf(
|
||||||
|
r.Uint32()%5 + 1,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
Reference in new issue
Block a user