Skip to content

Commit

Permalink
slice: 聚合函数 Max, Min 和 Sum
Browse files Browse the repository at this point in the history
  • Loading branch information
flycash committed Sep 11, 2022
1 parent 85cd66b commit 8b637f9
Show file tree
Hide file tree
Showing 4 changed files with 289 additions and 1 deletion.
3 changes: 2 additions & 1 deletion .CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,5 @@
- [ekit: 实现了 TaskPool](https://github.com/gotomicro/ekit/pull/57)
- [ekit: 修复OnDemandBlockTaskPool测试不稳定](https://github.com/gotomicro/ekit/pull/70)
- [syncx: 使用泛型封装 sync.Map](https://github.com/gotomicro/ekit/pull/79)
- [slice: 支持 Diff*, Intersection*, Union*, Index* 类方法](https://github.com/gotomicro/ekit/pull/83)
- [slice: 支持 Diff*, Intersection*, Union*, Index* 类方法](https://github.com/gotomicro/ekit/pull/83)
- [slice: 聚合函数 Max, Min 和 Sum](https://github.com/gotomicro/ekit/pull/82)
27 changes: 27 additions & 0 deletions constrain.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright 2021 gotomicro
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package ekit

// RealNumber 实数
// 绝大多数情况下,你都应该用这个来表达数字的含义
type RealNumber interface {
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 |
~int | ~int8 | ~int16 | ~int32 | ~int64 |
~float32 | ~float64
}

type Number interface {
RealNumber | ~complex64 | ~complex128
}
55 changes: 55 additions & 0 deletions slice/aggregate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright 2021 gotomicro
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package slice

import (
"github.com/gotomicro/ekit"
)

// Max 返回最大值。
// 该方法假设你至少会传入一个值。
// 在使用 float32 或者 float64 的时候要小心精度问题
func Max[T ekit.RealNumber](ts []T) T {
res := ts[0]
for i := 1; i < len(ts); i++ {
if ts[i] > res {
res = ts[i]
}
}
return res
}

// Min 返回最小值
// 该方法会假设你至少会传入一个值
// 在使用 float32 或者 float64 的时候要小心精度问题
func Min[T ekit.RealNumber](ts []T) T {
res := ts[0]
for i := 1; i < len(ts); i++ {
if ts[i] < res {
res = ts[i]
}
}
return res
}

// Sum 求和
// 在使用 float32 或者 float64 的时候要小心精度问题
func Sum[T ekit.Number](ts []T) T {
var res T
for _, n := range ts {
res += n
}
return res
}
205 changes: 205 additions & 0 deletions slice/aggregate_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
// Copyright 2021 gotomicro
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package slice

import (
"fmt"
"testing"

"github.com/gotomicro/ekit"

"github.com/stretchr/testify/assert"
)

func TestMax(t *testing.T) {
testCases := []struct {
name string
input []Integer
want Integer
}{
{
name: "value",
input: []Integer{1},
want: 1,
},
{
name: "values",
input: []Integer{2, 3, 1},
want: 3,
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
res := Max[Integer](tc.input)
assert.Equal(t, tc.want, res)
})
}

assert.Panics(t, func() {
Max[int](nil)
})
assert.Panics(t, func() {
Max[int]([]int{})
})

testMaxTypes[uint](t)
testMaxTypes[uint8](t)
testMaxTypes[uint16](t)
testMaxTypes[uint32](t)
testMaxTypes[uint64](t)
testMaxTypes[int](t)
testMaxTypes[int8](t)
testMaxTypes[int16](t)
testMaxTypes[int32](t)
testMaxTypes[int64](t)
testMaxTypes[float32](t)
testMaxTypes[float64](t)
}

func TestMin(t *testing.T) {
testCases := []struct {
name string
input []Integer
want Integer
}{
{
name: "value",
input: []Integer{3},
want: 3,
},
{
name: "values",
input: []Integer{3, 1, 2},
want: 1,
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
res := Min[Integer](tc.input)
assert.Equal(t, tc.want, res)
})
}

assert.Panics(t, func() {
Min[int](nil)
})
assert.Panics(t, func() {
Min[int]([]int{})
})

testMinTypes[uint](t)
testMinTypes[uint8](t)
testMinTypes[uint16](t)
testMinTypes[uint32](t)
testMinTypes[uint64](t)
testMinTypes[int](t)
testMinTypes[int8](t)
testMinTypes[int16](t)
testMinTypes[int32](t)
testMinTypes[int64](t)
testMinTypes[float32](t)
testMinTypes[float64](t)
}

func TestSum(t *testing.T) {
testCases := []struct {
name string
input []Integer
want Integer
}{
{
name: "nil",
},
{
name: "empty",
input: []Integer{},
},
{
name: "value",
input: []Integer{1},
want: 1,
},
{
name: "values",
input: []Integer{1, 2, 3},
want: 6,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
res := Sum[Integer](tc.input)
assert.Equal(t, tc.want, res)
})
}

testSumTypes[uint](t)
testSumTypes[uint8](t)
testSumTypes[uint16](t)
testSumTypes[uint32](t)
testSumTypes[uint64](t)
testSumTypes[int](t)
testSumTypes[int8](t)
testSumTypes[int16](t)
testSumTypes[int32](t)
testSumTypes[int64](t)
testSumTypes[float32](t)
testSumTypes[float64](t)
}

// testMaxTypes 只是用来测试一下满足 Max 方法约束的所有类型
func testMaxTypes[T ekit.RealNumber](t *testing.T) {
res := Max[T]([]T{1, 2, 3})
assert.Equal(t, T(3), res)
}

// testMinTypes 只是用来测试一下满足 Min 方法约束的所有类型
func testMinTypes[T ekit.RealNumber](t *testing.T) {
res := Min[T]([]T{1, 2, 3})
assert.Equal(t, T(1), res)
}

// testSumTypes 只是用来测试一下满足 Sum 方法约束的所有类型
func testSumTypes[T ekit.RealNumber](t *testing.T) {
res := Sum[T]([]T{1, 2, 3})
assert.Equal(t, T(6), res)
}

type Integer int

func ExampleSum() {
res := Sum[int]([]int{1, 2, 3})
fmt.Println(res)
res = Sum[int](nil)
fmt.Println(res)
// Output:
// 6
// 0
}

func ExampleMin() {
res := Min[int]([]int{1, 2, 3})
fmt.Println(res)
// Output:
// 1
}

func ExampleMax() {
res := Max[int]([]int{1, 2, 3})
fmt.Println(res)
// Output:
// 3
}

0 comments on commit 8b637f9

Please sign in to comment.