Skip to content

Commit

Permalink
ForEach functions (#57)
Browse files Browse the repository at this point in the history
ForEach pack of functions.
  • Loading branch information
kalaninja committed Jan 10, 2017
1 parent 09a5b98 commit 29256b8
Show file tree
Hide file tree
Showing 3 changed files with 189 additions and 0 deletions.
64 changes: 64 additions & 0 deletions example_test.go
Expand Up @@ -1735,6 +1735,70 @@ func ExampleQuery_FirstWithT() {

}

// The following code example demonstrates how to use ForEach
// to output all elements of an array.
func ExampleQuery_ForEach() {
fruits := []string{"orange", "apple", "lemon", "apple"}

From(fruits).ForEach(func(fruit interface{}) {
fmt.Println(fruit)
})

// Output:
// orange
// apple
// lemon
// apple
}

// The following code example demonstrates how to use ForEachIndexed
// to output all elements of an array with its index.
func ExampleQuery_ForEachIndexed() {
fruits := []string{"orange", "apple", "lemon", "apple"}

From(fruits).ForEachIndexed(func(i int, fruit interface{}) {
fmt.Printf("%d.%s\n", i, fruit)
})

// Output:
// 0.orange
// 1.apple
// 2.lemon
// 3.apple
}

// The following code example demonstrates how to use ForEachT
// to output all elements of an array.
func ExampleQuery_ForEachT() {
fruits := []string{"orange", "apple", "lemon", "apple"}

From(fruits).ForEachT(func(fruit string) {
fmt.Println(fruit)
})

// Output:
// orange
// apple
// lemon
// apple
}

// The following code example demonstrates how to use ForEachIndexedT
// to output all elements of an array with its index.
func ExampleQuery_ForEachIndexedT() {
fruits := []string{"orange", "apple", "lemon", "apple"}

From(fruits).ForEachIndexedT(func(i int, fruit string) {
fmt.Printf("%d.%s\n", i, fruit)
})

// Output:
// 0.orange
// 1.apple
// 2.lemon
// 3.apple
}

// The following code example demonstrates how to use GroupByT
// to group the elements of a slice.
func ExampleQuery_GroupByT() {
Expand Down
71 changes: 71 additions & 0 deletions result.go
Expand Up @@ -225,6 +225,77 @@ func (q Query) FirstWithT(predicateFn interface{}) interface{} {
return q.FirstWith(predicateFunc)
}

// ForEach performs the specified action on each element of a collection.
func (q Query) ForEach(action func(interface{})) {
next := q.Iterate()

for item, ok := next(); ok; item, ok = next() {
action(item)
}
}

// ForEachT is the typed version of ForEach.
//
// - actionFn is of type "func(TSource)"
//
// NOTE: ForEach has better performance than ForEachT.
func (q Query) ForEachT(actionFn interface{}) {
actionGenericFunc, err := newGenericFunc(
"ForEachT", "actionFn", actionFn,
simpleParamValidator(newElemTypeSlice(new(genericType)), nil),
)

if err != nil {
panic(err)
}

actionFunc := func(item interface{}) {
actionGenericFunc.Call(item)
}

q.ForEach(actionFunc)
}

// ForEachIndexed performs the specified action on each element of a collection.
//
// The first argument to action represents the zero-based index of that
// element in the source collection. This can be useful if the elements are in a
// known order and you want to do something with an element at a particular
// index, for example. It can also be useful if you want to retrieve the index
// of one or more elements. The second argument to action represents the
// element to process.
func (q Query) ForEachIndexed(action func(int, interface{})) {
next := q.Iterate()
index := 0

for item, ok := next(); ok; item, ok = next() {
action(index, item)
index++
}
}

// ForEachIndexedT is the typed version of ForEachIndexed.
//
// - actionFn is of type "func(int, TSource)"
//
// NOTE: ForEachIndexed has better performance than ForEachIndexedT.
func (q Query) ForEachIndexedT(actionFn interface{}) {
actionGenericFunc, err := newGenericFunc(
"ForEachIndexedT", "actionFn", actionFn,
simpleParamValidator(newElemTypeSlice(new(int), new(genericType)), nil),
)

if err != nil {
panic(err)
}

actionFunc := func(index int, item interface{}) {
actionGenericFunc.Call(index, item)
}

q.ForEachIndexed(actionFunc)
}

// Last returns the last element of a collection.
func (q Query) Last() (r interface{}) {
next := q.Iterate()
Expand Down
54 changes: 54 additions & 0 deletions result_test.go
Expand Up @@ -197,6 +197,60 @@ func TestFirstWithT_PanicWhenPredicateFnIsInvalid(t *testing.T) {
})
}

func TestForEach(t *testing.T) {
tests := []struct {
input interface{}
want interface{}
}{
{[5]int{1, 2, 2, 35, 111}, []int{2, 4, 4, 70, 222}},
{[]int{}, []int{}},
}

for _, test := range tests {
output := []int{}
From(test.input).ForEach(func(item interface{}) {
output = append(output, item.(int)*2)
})

if !reflect.DeepEqual(output, test.want) {
t.Fatalf("From(%#v).ForEach()=%#v expected=%#v", test.input, output, test.want)
}
}
}

func TestForEachT_PanicWhenActionFnIsInvalid(t *testing.T) {
mustPanicWithError(t, "ForEachT: parameter [actionFn] has a invalid function signature. Expected: 'func(T)', actual: 'func(int,int)'", func() {
From([]int{1, 1, 1, 2, 1, 2, 3, 4, 2}).ForEachT(func(item, idx int) { item = item + 2 })
})
}

func TestForEachIndexed(t *testing.T) {
tests := []struct {
input interface{}
want interface{}
}{
{[5]int{1, 2, 2, 35, 111}, []int{1, 3, 4, 38, 115}},
{[]int{}, []int{}},
}

for _, test := range tests {
output := []int{}
From(test.input).ForEachIndexed(func(index int, item interface{}) {
output = append(output, item.(int)+index)
})

if !reflect.DeepEqual(output, test.want) {
t.Fatalf("From(%#v).ForEachIndexed()=%#v expected=%#v", test.input, output, test.want)
}
}
}

func TestForEachIndexedT_PanicWhenActionFnIsInvalid(t *testing.T) {
mustPanicWithError(t, "ForEachIndexedT: parameter [actionFn] has a invalid function signature. Expected: 'func(int,T)', actual: 'func(int)'", func() {
From([]int{1, 1, 1, 2, 1, 2, 3, 4, 2}).ForEachIndexedT(func(item int) { item = item + 2 })
})
}

func TestLast(t *testing.T) {
tests := []struct {
input interface{}
Expand Down

0 comments on commit 29256b8

Please sign in to comment.