diff --git a/go.mod b/go.mod index 67fb391..69c6c1c 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/upfluence/pkg -go 1.21 +go 1.23 require ( github.com/Microsoft/go-winio v0.4.14 // indirect @@ -33,8 +33,9 @@ require ( github.com/upfluence/log v0.0.5 github.com/upfluence/stats v0.1.4 github.com/upfluence/thrift v2.4.4+incompatible + golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 golang.org/x/oauth2 v0.19.0 - golang.org/x/sync v0.4.0 + golang.org/x/sync v0.8.0 golang.org/x/term v0.13.0 golang.org/x/text v0.13.0 golang.org/x/time v0.3.0 diff --git a/go.sum b/go.sum index 4da9e9b..cda3347 100644 --- a/go.sum +++ b/go.sum @@ -178,8 +178,8 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= @@ -513,6 +513,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -558,8 +560,8 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= -golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -615,8 +617,8 @@ golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE= +golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/slices/reduce.go b/slices/reduce.go new file mode 100644 index 0000000..1879c1c --- /dev/null +++ b/slices/reduce.go @@ -0,0 +1,20 @@ +package slices + +// ReduceFrom will iterate over each element of slice and call reduceFn for each. +// The return value of each reduceFn is passed to the next call of reduceFn as acc, or +// in other term at each iteration on the slice. +func ReduceFrom[S ~[]E, E any, A any](slice S, acc A, reduceFn func(acc A, elem E) A) A { + for _, e := range slice { + acc = reduceFn(acc, e) + } + + return acc +} + +// Reduce does the same as ReduceFrom but use the zero value of A as +// the first value to be passed to reduceFn. +func Reduce[S ~[]E, E any, A any](slice S, reduceFn func(acc A, elem E) A) A { + var acc A + + return ReduceFrom(slice, acc, reduceFn) +} diff --git a/slices/reduce_test.go b/slices/reduce_test.go new file mode 100644 index 0000000..a57b322 --- /dev/null +++ b/slices/reduce_test.go @@ -0,0 +1,42 @@ +package slices + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestReduceWith(t *testing.T) { + for _, tt := range []struct { + slice []int + acc int + fn func(int, int) int + want int + }{ + {slice: []int{1, 2, 3}, acc: 0, fn: func(a, b int) int { return a + b }, want: 6}, + {slice: []int{1, 2, 3}, acc: 1, fn: func(a, b int) int { return a * b }, want: 6}, + {slice: []int{}, acc: 0, fn: func(a, b int) int { return a + b }, want: 0}, + {slice: []int{1}, acc: 0, fn: func(a, b int) int { return a + b }, want: 1}, + } { + t.Run("", func(t *testing.T) { + got := ReduceFrom(tt.slice, tt.acc, tt.fn) + assert.Equal(t, tt.want, got) + }) + } +} + +func TestReduce(t *testing.T) { + for _, tt := range []struct { + slice []int + fn func(int, int) int + want int + }{ + {slice: []int{1, 2, 3}, fn: func(a, b int) int { return a + b }, want: 6}, + {slice: []int{1, 2, 3}, fn: func(a, b int) int { return a * b }, want: 0}, + {slice: []int{}, fn: func(a, b int) int { return a + b }, want: 0}, + {slice: []int{1}, fn: func(a, b int) int { return a + b }, want: 1}, + } { + got := Reduce(tt.slice, tt.fn) + assert.Equal(t, tt.want, got) + } +}