Skip to content

Commit 29256b8

Browse files
authored
ForEach functions (#57)
ForEach pack of functions.
1 parent 09a5b98 commit 29256b8

File tree

3 files changed

+189
-0
lines changed

3 files changed

+189
-0
lines changed

example_test.go

+64
Original file line numberDiff line numberDiff line change
@@ -1735,6 +1735,70 @@ func ExampleQuery_FirstWithT() {
17351735

17361736
}
17371737

1738+
// The following code example demonstrates how to use ForEach
1739+
// to output all elements of an array.
1740+
func ExampleQuery_ForEach() {
1741+
fruits := []string{"orange", "apple", "lemon", "apple"}
1742+
1743+
From(fruits).ForEach(func(fruit interface{}) {
1744+
fmt.Println(fruit)
1745+
})
1746+
1747+
// Output:
1748+
// orange
1749+
// apple
1750+
// lemon
1751+
// apple
1752+
}
1753+
1754+
// The following code example demonstrates how to use ForEachIndexed
1755+
// to output all elements of an array with its index.
1756+
func ExampleQuery_ForEachIndexed() {
1757+
fruits := []string{"orange", "apple", "lemon", "apple"}
1758+
1759+
From(fruits).ForEachIndexed(func(i int, fruit interface{}) {
1760+
fmt.Printf("%d.%s\n", i, fruit)
1761+
})
1762+
1763+
// Output:
1764+
// 0.orange
1765+
// 1.apple
1766+
// 2.lemon
1767+
// 3.apple
1768+
}
1769+
1770+
// The following code example demonstrates how to use ForEachT
1771+
// to output all elements of an array.
1772+
func ExampleQuery_ForEachT() {
1773+
fruits := []string{"orange", "apple", "lemon", "apple"}
1774+
1775+
From(fruits).ForEachT(func(fruit string) {
1776+
fmt.Println(fruit)
1777+
})
1778+
1779+
// Output:
1780+
// orange
1781+
// apple
1782+
// lemon
1783+
// apple
1784+
}
1785+
1786+
// The following code example demonstrates how to use ForEachIndexedT
1787+
// to output all elements of an array with its index.
1788+
func ExampleQuery_ForEachIndexedT() {
1789+
fruits := []string{"orange", "apple", "lemon", "apple"}
1790+
1791+
From(fruits).ForEachIndexedT(func(i int, fruit string) {
1792+
fmt.Printf("%d.%s\n", i, fruit)
1793+
})
1794+
1795+
// Output:
1796+
// 0.orange
1797+
// 1.apple
1798+
// 2.lemon
1799+
// 3.apple
1800+
}
1801+
17381802
// The following code example demonstrates how to use GroupByT
17391803
// to group the elements of a slice.
17401804
func ExampleQuery_GroupByT() {

result.go

+71
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,77 @@ func (q Query) FirstWithT(predicateFn interface{}) interface{} {
225225
return q.FirstWith(predicateFunc)
226226
}
227227

228+
// ForEach performs the specified action on each element of a collection.
229+
func (q Query) ForEach(action func(interface{})) {
230+
next := q.Iterate()
231+
232+
for item, ok := next(); ok; item, ok = next() {
233+
action(item)
234+
}
235+
}
236+
237+
// ForEachT is the typed version of ForEach.
238+
//
239+
// - actionFn is of type "func(TSource)"
240+
//
241+
// NOTE: ForEach has better performance than ForEachT.
242+
func (q Query) ForEachT(actionFn interface{}) {
243+
actionGenericFunc, err := newGenericFunc(
244+
"ForEachT", "actionFn", actionFn,
245+
simpleParamValidator(newElemTypeSlice(new(genericType)), nil),
246+
)
247+
248+
if err != nil {
249+
panic(err)
250+
}
251+
252+
actionFunc := func(item interface{}) {
253+
actionGenericFunc.Call(item)
254+
}
255+
256+
q.ForEach(actionFunc)
257+
}
258+
259+
// ForEachIndexed performs the specified action on each element of a collection.
260+
//
261+
// The first argument to action represents the zero-based index of that
262+
// element in the source collection. This can be useful if the elements are in a
263+
// known order and you want to do something with an element at a particular
264+
// index, for example. It can also be useful if you want to retrieve the index
265+
// of one or more elements. The second argument to action represents the
266+
// element to process.
267+
func (q Query) ForEachIndexed(action func(int, interface{})) {
268+
next := q.Iterate()
269+
index := 0
270+
271+
for item, ok := next(); ok; item, ok = next() {
272+
action(index, item)
273+
index++
274+
}
275+
}
276+
277+
// ForEachIndexedT is the typed version of ForEachIndexed.
278+
//
279+
// - actionFn is of type "func(int, TSource)"
280+
//
281+
// NOTE: ForEachIndexed has better performance than ForEachIndexedT.
282+
func (q Query) ForEachIndexedT(actionFn interface{}) {
283+
actionGenericFunc, err := newGenericFunc(
284+
"ForEachIndexedT", "actionFn", actionFn,
285+
simpleParamValidator(newElemTypeSlice(new(int), new(genericType)), nil),
286+
)
287+
288+
if err != nil {
289+
panic(err)
290+
}
291+
292+
actionFunc := func(index int, item interface{}) {
293+
actionGenericFunc.Call(index, item)
294+
}
295+
296+
q.ForEachIndexed(actionFunc)
297+
}
298+
228299
// Last returns the last element of a collection.
229300
func (q Query) Last() (r interface{}) {
230301
next := q.Iterate()

result_test.go

+54
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,60 @@ func TestFirstWithT_PanicWhenPredicateFnIsInvalid(t *testing.T) {
197197
})
198198
}
199199

200+
func TestForEach(t *testing.T) {
201+
tests := []struct {
202+
input interface{}
203+
want interface{}
204+
}{
205+
{[5]int{1, 2, 2, 35, 111}, []int{2, 4, 4, 70, 222}},
206+
{[]int{}, []int{}},
207+
}
208+
209+
for _, test := range tests {
210+
output := []int{}
211+
From(test.input).ForEach(func(item interface{}) {
212+
output = append(output, item.(int)*2)
213+
})
214+
215+
if !reflect.DeepEqual(output, test.want) {
216+
t.Fatalf("From(%#v).ForEach()=%#v expected=%#v", test.input, output, test.want)
217+
}
218+
}
219+
}
220+
221+
func TestForEachT_PanicWhenActionFnIsInvalid(t *testing.T) {
222+
mustPanicWithError(t, "ForEachT: parameter [actionFn] has a invalid function signature. Expected: 'func(T)', actual: 'func(int,int)'", func() {
223+
From([]int{1, 1, 1, 2, 1, 2, 3, 4, 2}).ForEachT(func(item, idx int) { item = item + 2 })
224+
})
225+
}
226+
227+
func TestForEachIndexed(t *testing.T) {
228+
tests := []struct {
229+
input interface{}
230+
want interface{}
231+
}{
232+
{[5]int{1, 2, 2, 35, 111}, []int{1, 3, 4, 38, 115}},
233+
{[]int{}, []int{}},
234+
}
235+
236+
for _, test := range tests {
237+
output := []int{}
238+
From(test.input).ForEachIndexed(func(index int, item interface{}) {
239+
output = append(output, item.(int)+index)
240+
})
241+
242+
if !reflect.DeepEqual(output, test.want) {
243+
t.Fatalf("From(%#v).ForEachIndexed()=%#v expected=%#v", test.input, output, test.want)
244+
}
245+
}
246+
}
247+
248+
func TestForEachIndexedT_PanicWhenActionFnIsInvalid(t *testing.T) {
249+
mustPanicWithError(t, "ForEachIndexedT: parameter [actionFn] has a invalid function signature. Expected: 'func(int,T)', actual: 'func(int)'", func() {
250+
From([]int{1, 1, 1, 2, 1, 2, 3, 4, 2}).ForEachIndexedT(func(item int) { item = item + 2 })
251+
})
252+
}
253+
200254
func TestLast(t *testing.T) {
201255
tests := []struct {
202256
input interface{}

0 commit comments

Comments
 (0)