mirror of
https://github.com/duke-git/lancet.git
synced 2026-03-01 00:35:28 +08:00
feat: add Distinct
This commit is contained in:
@@ -6,7 +6,12 @@
|
|||||||
// powerful like other libs
|
// powerful like other libs
|
||||||
package stream
|
package stream
|
||||||
|
|
||||||
import "golang.org/x/exp/constraints"
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/gob"
|
||||||
|
|
||||||
|
"golang.org/x/exp/constraints"
|
||||||
|
)
|
||||||
|
|
||||||
// A stream should implements methods:
|
// A stream should implements methods:
|
||||||
// type StreamI[T any] interface {
|
// type StreamI[T any] interface {
|
||||||
@@ -69,6 +74,34 @@ func FromRange[T constraints.Integer | constraints.Float](start, end, step T) st
|
|||||||
return stream[T]{source: source}
|
return stream[T]{source: source}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Distinct returns a stream that removes the duplicated items.
|
||||||
|
func (s stream[T]) Distinct() stream[T] {
|
||||||
|
source := make([]T, 0)
|
||||||
|
|
||||||
|
distinct := map[string]bool{}
|
||||||
|
|
||||||
|
for _, v := range s.source {
|
||||||
|
// todo: performance issue
|
||||||
|
k := hashKey(v)
|
||||||
|
if _, ok := distinct[k]; !ok {
|
||||||
|
distinct[k] = true
|
||||||
|
source = append(source, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FromSlice(source)
|
||||||
|
}
|
||||||
|
|
||||||
|
func hashKey(data any) string {
|
||||||
|
buffer := bytes.NewBuffer(nil)
|
||||||
|
encoder := gob.NewEncoder(buffer)
|
||||||
|
err := encoder.Encode(data)
|
||||||
|
if err != nil {
|
||||||
|
panic("stream.hashKey: get hashkey failed")
|
||||||
|
}
|
||||||
|
return buffer.String()
|
||||||
|
}
|
||||||
|
|
||||||
// ToSlice return the elements in the stream.
|
// ToSlice return the elements in the stream.
|
||||||
func (s stream[T]) ToSlice() []T {
|
func (s stream[T]) ToSlice() []T {
|
||||||
return s.source
|
return s.source
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ func TestFromSlice(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestFromRange(t *testing.T) {
|
func TestFromRange(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestFromSlice")
|
assert := internal.NewAssert(t, "TestFromRange")
|
||||||
|
|
||||||
s1 := FromRange(1, 5, 1)
|
s1 := FromRange(1, 5, 1)
|
||||||
s2 := FromRange(1.1, 5.0, 1.0)
|
s2 := FromRange(1.1, 5.0, 1.0)
|
||||||
@@ -23,3 +23,35 @@ func TestFromRange(t *testing.T) {
|
|||||||
assert.Equal([]int{1, 2, 3, 4, 5}, s1.ToSlice())
|
assert.Equal([]int{1, 2, 3, 4, 5}, s1.ToSlice())
|
||||||
assert.Equal([]float64{1.1, 2.1, 3.1, 4.1}, s2.ToSlice())
|
assert.Equal([]float64{1.1, 2.1, 3.1, 4.1}, s2.ToSlice())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestStream_Distinct(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestStream_Distinct")
|
||||||
|
|
||||||
|
nums := FromSlice([]int{1, 2, 2, 3, 3, 3})
|
||||||
|
distinctNums := nums.Distinct()
|
||||||
|
|
||||||
|
assert.Equal([]int{1, 2, 2, 3, 3, 3}, nums.ToSlice())
|
||||||
|
assert.Equal([]int{1, 2, 3}, distinctNums.ToSlice())
|
||||||
|
|
||||||
|
type Person struct {
|
||||||
|
Id string
|
||||||
|
Name string
|
||||||
|
Age uint
|
||||||
|
}
|
||||||
|
|
||||||
|
people := []Person{
|
||||||
|
{Id: "001", Name: "Tom", Age: 10},
|
||||||
|
{Id: "001", Name: "Tom", Age: 10},
|
||||||
|
{Id: "002", Name: "Jim", Age: 20},
|
||||||
|
{Id: "003", Name: "Mike", Age: 30},
|
||||||
|
}
|
||||||
|
|
||||||
|
stream := FromSlice(people)
|
||||||
|
distinctStream := stream.Distinct()
|
||||||
|
|
||||||
|
// {[{001 Tom 10} {001 Tom 10} {002 Jim 20} {003 Mike 30}]}
|
||||||
|
t.Log(stream)
|
||||||
|
|
||||||
|
// {[{001 Tom 10} {002 Jim 20} {003 Mike 30}]}
|
||||||
|
t.Log(distinctStream)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user