Skip to content

Commit

Permalink
Add more functions (#35)
Browse files Browse the repository at this point in the history
  • Loading branch information
mokiat authored Nov 9, 2024
1 parent 2a612a2 commit 1e307b5
Show file tree
Hide file tree
Showing 9 changed files with 205 additions and 2 deletions.
27 changes: 27 additions & 0 deletions constr/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Package constr provides a set of constraints for Go generics.
package constr

// Integer represents a type that is a signed or unsigned integer.
type Integer interface {
Signed | Unsigned
}

// Signed represents a type that is a signed integer.
type Signed interface {
~int | ~int8 | ~int16 | ~int32 | ~int64
}

// Unsigned represents a type that is an unsigned integer.
type Unsigned interface {
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64
}

// Float represents a type that is a floating-point number.
type Float interface {
~float32 | ~float64
}

// Numeric represents a type that is a number.
type Numeric interface {
Integer | Float
}
9 changes: 9 additions & 0 deletions example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,3 +226,12 @@ func ExampleMerge() {
// 2: "even"
// 10000: "large"
}

func ExampleSum() {
source := []int{1, 2, 3}
target := gog.Sum(source)
fmt.Println(target)

// Output:
// 6
}
35 changes: 35 additions & 0 deletions seq/example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package seq_test

import (
"fmt"
"slices"

"github.com/mokiat/gog/seq"
)
Expand Down Expand Up @@ -81,3 +82,37 @@ func ExampleBatchSlice() {
// []string{"2This", "2Is", "2Longer"}
// []string{"3Yes"}
}

func ExampleSelect() {
source := slices.Values([]int{1, 2, 3, 4, 5})
target := seq.Select(source, func(v int) bool {
return v%2 == 0
})
for v := range target {
fmt.Println(v)
}

// Output:
// 2
// 4
}

func ExampleReduce() {
source := slices.Values([]int{1, 2, 3})
result := seq.Reduce(source, 10, func(acc, v int) int {
return acc + v
})
fmt.Println(result)

// Output:
// 16
}

func ExampleSum() {
source := slices.Values([]int{1, 2, 3})
result := seq.Sum(source)
fmt.Println(result)

// Output:
// 6
}
19 changes: 19 additions & 0 deletions seq/filter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package seq

import "iter"

// Select applies the given predicate function to each element of the source
// sequence and returns a new sequence with the elements for which the predicate
// returned true.
func Select[T any](src iter.Seq[T], pred func(T) bool) iter.Seq[T] {
return func(yield func(T) bool) {
for item := range src {
if !pred(item) {
continue
}
if !yield(item) {
return
}
}
}
}
27 changes: 27 additions & 0 deletions seq/filter_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package seq_test

import (
"slices"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

"github.com/mokiat/gog/seq"
)

var _ = Describe("Filter", func() {

Describe("Select", func() {
isEven := func(value int) bool {
return value%2 == 0
}

It("returns only the elements that match the predicate", func() {
source := slices.Values([]int{1, 2, 3, 4, 5})
target := seq.Select(source, isEven)
items := slices.Collect(target)
Expect(items).To(Equal([]int{2, 4}))
})
})

})
29 changes: 28 additions & 1 deletion seq/transform.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package seq

import "iter"
import (
"iter"

"github.com/mokiat/gog/constr"
)

// Map applies the given transformation function to each element of the source
// sequence and returns a new sequence with the results.
Expand Down Expand Up @@ -65,3 +69,26 @@ func BatchSliceFast[T any](items []T, eqFunc func(items []T, i, j int) bool, max
}
}
}

// Reduce compacts a sequence into a single value. The provided function is used
// to perform the reduction starting with the initialValue.
func Reduce[T any, S any](src iter.Seq[S], initialValue T, fn func(accum T, valye S) T) T {
accum := initialValue
for v := range src {
accum = fn(accum, v)
}
return accum
}

// Sum is a convenience function that calculates the sum of all elements in the
// source sequence.
//
// The same can normally be achieved with the Reduce function, but this function
// is simpler to use and faster.
func Sum[T constr.Numeric](src iter.Seq[T]) T {
var result T
for v := range src {
result += v
}
return result
}
26 changes: 26 additions & 0 deletions seq/transform_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,30 @@ var _ = Describe("Transform", func() {
}))
})
})

Describe("Reduce", func() {
It("reduces a sequence to a single value", func() {
source := slices.Values([]int{1, 2, 3})
result := seq.Reduce(source, ">", func(accum string, value int) string {
return accum + strconv.Itoa(value)
})
Expect(result).To(Equal(">123"))
})
})

Describe("Sum", func() {
type IntWrapper int

It("calculates the sum of the sequence", func() {
source := slices.Values([]IntWrapper{0, 1, 2, 3})
result := seq.Sum(source)
Expect(result).To(Equal(IntWrapper(6)))
})

It("returns the zero value for empty sequence", func() {
source := slices.Values([]int{})
result := seq.Sum(source)
Expect(result).To(Equal(0))
})
})
})
19 changes: 18 additions & 1 deletion slice.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package gog

import "maps"
import (
"maps"

"github.com/mokiat/gog/constr"
)

// Map can be used to transform one slice into another by providing a
// function to do the mapping.
Expand Down Expand Up @@ -201,3 +205,16 @@ func Merge[K comparable, V any](ms ...map[K]V) map[K]V {
}
return result
}

// Sum is a convenience function that calculates the sum of all elements in the
// source slice.
//
// The same can normally be achieved with the Reduce function, but this function
// is simpler to use and faster.
func Sum[T constr.Numeric](src []T) T {
var result T
for _, v := range src {
result += v
}
return result
}
16 changes: 16 additions & 0 deletions slice_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -322,4 +322,20 @@ var _ = Describe("Slice", func() {
Expect(result).To(Equal(map[int]string{}))
})
})

Describe("Sum", func() {
type IntWrapper int

It("calculates the sum of the slice", func() {
source := []IntWrapper{0, 1, 2, 3}
result := gog.Sum(source)
Expect(result).To(Equal(IntWrapper(6)))
})

It("returns the zero value for empty slices", func() {
source := []int{}
result := gog.Sum(source)
Expect(result).To(Equal(0))
})
})
})

0 comments on commit 1e307b5

Please sign in to comment.