1
0
mirror of https://github.com/duke-git/lancet.git synced 2026-03-01 00:35:28 +08:00

Compare commits

...

6 Commits

Author SHA1 Message Date
dudaodong
84da7d4f27 feat: add RandUpper, RandLower, RandNumeral, and RandNumeralOrLetter 2022-11-06 20:04:52 +08:00
dudaodong
089fd4e13c feat: add UnionBy for slice 2022-11-05 19:45:34 +08:00
dudaodong
6c40e02324 refactor: clean code 2022-11-05 19:33:56 +08:00
dudaodong
a270b1b634 feat: make code clear 2022-11-05 17:09:56 +08:00
dudaodong
260fb795d3 feat: add KeyBy for slice 2022-11-05 16:52:31 +08:00
dudaodong
8c036f830c refactor: remove unuseful code 2022-11-05 16:39:42 +08:00
4 changed files with 169 additions and 91 deletions

View File

@@ -12,18 +12,12 @@ import (
"time" "time"
) )
// RandString generate random string const (
// see https://stackoverflow.com/questions/22892120/how-to-generate-a-random-string-of-a-fixed-length-in-go NUMERAL = "0123456789"
func RandString(length int) string { LOWER_LETTERS = "abcdefghijklmnopqrstuvwxyz"
const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" UPPER_LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
LETTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
b := make([]byte, length) )
r := rand.New(rand.NewSource(time.Now().UnixNano()))
for i := range b {
b[i] = letters[r.Int63()%int64(len(letters))]
}
return string(b)
}
// RandInt generate random int between min and max, maybe min, not be max // RandInt generate random int between min and max, maybe min, not be max
func RandInt(min, max int) int { func RandInt(min, max int) int {
@@ -50,6 +44,41 @@ func RandBytes(length int) []byte {
return b return b
} }
// RandString generate random string
func RandString(length int) string {
return random(LETTERS, length)
}
// RandUpper generate a random upper case string
func RandUpper(length int) string {
return random(UPPER_LETTERS, length)
}
// RandLower generate a random lower case string
func RandLower(length int) string {
return random(LOWER_LETTERS, length)
}
// RandNumeral generate a random numeral string
func RandNumeral(length int) string {
return random(NUMERAL, length)
}
// RandNumeralOrLetter generate a random numeral or letter string
func RandNumeralOrLetter(length int) string {
return random(NUMERAL+LETTERS, length)
}
// random generate a random string based on given string range
func random(s string, length int) string {
b := make([]byte, length)
r := rand.New(rand.NewSource(time.Now().UnixNano()))
for i := range b {
b[i] = s[r.Int63()%int64(len(s))]
}
return string(b)
}
// UUIdV4 generate a random UUID of version 4 according to RFC 4122 // UUIdV4 generate a random UUID of version 4 according to RFC 4122
func UUIdV4() (string, error) { func UUIdV4() (string, error) {
uuid := make([]byte, 16) uuid := make([]byte, 16)

View File

@@ -19,6 +19,51 @@ func TestRandString(t *testing.T) {
assert.Equal(true, reg.MatchString(randStr)) assert.Equal(true, reg.MatchString(randStr))
} }
func TestRandUpper(t *testing.T) {
pattern := `^[A-Z]+$`
reg := regexp.MustCompile(pattern)
randStr := RandUpper(6)
assert := internal.NewAssert(t, "TestRandUpper")
assert.Equal(6, len(randStr))
assert.Equal(true, reg.MatchString(randStr))
}
func TestRandLower(t *testing.T) {
pattern := `^[a-z]+$`
reg := regexp.MustCompile(pattern)
randStr := RandLower(6)
assert := internal.NewAssert(t, "TestRandLower")
assert.Equal(6, len(randStr))
assert.Equal(true, reg.MatchString(randStr))
}
func TestRandNumeral(t *testing.T) {
pattern := `^[0-9]+$`
reg := regexp.MustCompile(pattern)
randStr := RandNumeral(12)
assert := internal.NewAssert(t, "TestRandNumeral")
assert.Equal(12, len(randStr))
assert.Equal(true, reg.MatchString(randStr))
}
func TestRandNumeralOrLetter(t *testing.T) {
pattern := `^[0-9a-zA-Z]+$`
reg := regexp.MustCompile(pattern)
randStr := RandNumeralOrLetter(10)
t.Log(randStr)
assert := internal.NewAssert(t, "TestRandNumeralOrLetter")
assert.Equal(10, len(randStr))
assert.Equal(true, reg.MatchString(randStr))
}
func TestRandInt(t *testing.T) { func TestRandInt(t *testing.T) {
assert := internal.NewAssert(t, "TestRandInt") assert := internal.NewAssert(t, "TestRandInt")

View File

@@ -36,7 +36,7 @@ func ContainSubSlice[T comparable](slice, subslice []T) bool {
// Chunk creates an slice of elements split into groups the length of size. // Chunk creates an slice of elements split into groups the length of size.
func Chunk[T any](slice []T, size int) [][]T { func Chunk[T any](slice []T, size int) [][]T {
var result [][]T result := [][]T{}
if len(slice) == 0 || size <= 0 { if len(slice) == 0 || size <= 0 {
return result return result
@@ -95,7 +95,8 @@ func Concat[T any](slice []T, values ...[]T) []T {
// Difference creates an slice of whose element in slice but not in comparedSlice // Difference creates an slice of whose element in slice but not in comparedSlice
func Difference[T comparable](slice, comparedSlice []T) []T { func Difference[T comparable](slice, comparedSlice []T) []T {
var result []T result := []T{}
for _, v := range slice { for _, v := range slice {
if !Contain(comparedSlice, v) { if !Contain(comparedSlice, v) {
result = append(result, v) result = append(result, v)
@@ -123,7 +124,7 @@ func DifferenceBy[T comparable](slice []T, comparedSlice []T, iteratee func(inde
} }
//DifferenceWith accepts comparator which is invoked to compare elements of slice to values. The order and references of result values are determined by the first slice. The comparator is invoked with two arguments: (arrVal, othVal). //DifferenceWith accepts comparator which is invoked to compare elements of slice to values. The order and references of result values are determined by the first slice. The comparator is invoked with two arguments: (arrVal, othVal).
func DifferenceWith[T any](slice []T, comparedSlice []T, comparator func(value, otherValue T) bool) []T { func DifferenceWith[T any](slice []T, comparedSlice []T, comparator func(value1, value2 T) bool) []T {
result := make([]T, 0) result := make([]T, 0)
getIndex := func(arr []T, item T, comparison func(v1, v2 T) bool) int { getIndex := func(arr []T, item T, comparison func(v1, v2 T) bool) int {
@@ -180,11 +181,8 @@ func EqualWith[T, U any](slice1 []T, slice2 []U, comparator func(T, U) bool) boo
// Every return true if all of the values in the slice pass the predicate function. // Every return true if all of the values in the slice pass the predicate function.
func Every[T any](slice []T, predicate func(index int, item T) bool) bool { func Every[T any](slice []T, predicate func(index int, item T) bool) bool {
if predicate == nil {
panic("predicate func is missing")
}
var currentLength int var currentLength int
for i, v := range slice { for i, v := range slice {
if predicate(i, v) { if predicate(i, v) {
currentLength++ currentLength++
@@ -196,9 +194,6 @@ func Every[T any](slice []T, predicate func(index int, item T) bool) bool {
// None return true if all the values in the slice mismatch the criteria // None return true if all the values in the slice mismatch the criteria
func None[T any](slice []T, predicate func(index int, item T) bool) bool { func None[T any](slice []T, predicate func(index int, item T) bool) bool {
if predicate == nil {
panic("predicate func is missing")
}
var currentLength int var currentLength int
for i, v := range slice { for i, v := range slice {
@@ -212,39 +207,30 @@ func None[T any](slice []T, predicate func(index int, item T) bool) bool {
// Some return true if any of the values in the list pass the predicate function. // Some return true if any of the values in the list pass the predicate function.
func Some[T any](slice []T, predicate func(index int, item T) bool) bool { func Some[T any](slice []T, predicate func(index int, item T) bool) bool {
if predicate == nil {
panic("predicate func is missing")
}
for i, v := range slice { for i, v := range slice {
if predicate(i, v) { if predicate(i, v) {
return true return true
} }
} }
return false return false
} }
// Filter iterates over elements of slice, returning an slice of all elements pass the predicate function // Filter iterates over elements of slice, returning an slice of all elements pass the predicate function
func Filter[T any](slice []T, predicate func(index int, item T) bool) []T { func Filter[T any](slice []T, predicate func(index int, item T) bool) []T {
if predicate == nil {
panic("predicate func is missing")
}
result := make([]T, 0) result := make([]T, 0)
for i, v := range slice { for i, v := range slice {
if predicate(i, v) { if predicate(i, v) {
result = append(result, v) result = append(result, v)
} }
} }
return result return result
} }
// Count iterates over elements of slice, returns a count of all matched elements // Count iterates over elements of slice, returns a count of all matched elements
func Count[T any](slice []T, predicate func(index int, item T) bool) int { func Count[T any](slice []T, predicate func(index int, item T) bool) int {
if predicate == nil {
panic("predicate func is missing")
}
if len(slice) == 0 { if len(slice) == 0 {
return 0 return 0
} }
@@ -261,10 +247,6 @@ func Count[T any](slice []T, predicate func(index int, item T) bool) int {
// GroupBy iterate over elements of the slice, each element will be group by criteria, returns two slices // GroupBy iterate over elements of the slice, each element will be group by criteria, returns two slices
func GroupBy[T any](slice []T, groupFn func(index int, item T) bool) ([]T, []T) { func GroupBy[T any](slice []T, groupFn func(index int, item T) bool) ([]T, []T) {
if groupFn == nil {
panic("groupFn func is missing")
}
if len(slice) == 0 { if len(slice) == 0 {
return make([]T, 0), make([]T, 0) return make([]T, 0), make([]T, 0)
} }
@@ -285,11 +267,7 @@ func GroupBy[T any](slice []T, groupFn func(index int, item T) bool) ([]T, []T)
} }
// GroupWith return a map composed of keys generated from the resultults of running each element of slice thru iteratee. // GroupWith return a map composed of keys generated from the resultults of running each element of slice thru iteratee.
func GroupWith[T any, U comparable](slice []T, iteratee func(T) U) map[U][]T { func GroupWith[T any, U comparable](slice []T, iteratee func(item T) U) map[U][]T {
if iteratee == nil {
panic("iteratee func is missing")
}
result := make(map[U][]T) result := make(map[U][]T)
for _, v := range slice { for _, v := range slice {
@@ -306,10 +284,6 @@ func GroupWith[T any, U comparable](slice []T, iteratee func(T) U) map[U][]T {
// Find iterates over elements of slice, returning the first one that passes a truth test on predicate function. // Find iterates over elements of slice, returning the first one that passes a truth test on predicate function.
// If return T is nil then no items matched the predicate func // If return T is nil then no items matched the predicate func
func Find[T any](slice []T, predicate func(index int, item T) bool) (*T, bool) { func Find[T any](slice []T, predicate func(index int, item T) bool) (*T, bool) {
if predicate == nil {
panic("predicate func is missing")
}
if len(slice) == 0 { if len(slice) == 0 {
return nil, false return nil, false
} }
@@ -332,10 +306,6 @@ func Find[T any](slice []T, predicate func(index int, item T) bool) (*T, bool) {
// FindLast iterates over elements of slice from end to begin, returning the first one that passes a truth test on predicate function. // FindLast iterates over elements of slice from end to begin, returning the first one that passes a truth test on predicate function.
// If return T is nil then no items matched the predicate func // If return T is nil then no items matched the predicate func
func FindLast[T any](slice []T, predicate func(index int, item T) bool) (*T, bool) { func FindLast[T any](slice []T, predicate func(index int, item T) bool) (*T, bool) {
if predicate == nil {
panic("predicate func is missing")
}
if len(slice) == 0 { if len(slice) == 0 {
return nil, false return nil, false
} }
@@ -408,10 +378,6 @@ func flattenRecursive(value reflect.Value, result reflect.Value) reflect.Value {
// ForEach iterates over elements of slice and invokes function for each element // ForEach iterates over elements of slice and invokes function for each element
func ForEach[T any](slice []T, iteratee func(index int, item T)) { func ForEach[T any](slice []T, iteratee func(index int, item T)) {
if iteratee == nil {
panic("iteratee func is missing")
}
for i, v := range slice { for i, v := range slice {
iteratee(i, v) iteratee(i, v)
} }
@@ -419,10 +385,6 @@ func ForEach[T any](slice []T, iteratee func(index int, item T)) {
// Map creates an slice of values by running each element of slice thru iteratee function. // Map creates an slice of values by running each element of slice thru iteratee function.
func Map[T any, U any](slice []T, iteratee func(index int, item T) U) []U { func Map[T any, U any](slice []T, iteratee func(index int, item T) U) []U {
if iteratee == nil {
panic("iteratee func is missing")
}
result := make([]U, len(slice), cap(slice)) result := make([]U, len(slice), cap(slice))
for i, v := range slice { for i, v := range slice {
result[i] = iteratee(i, v) result[i] = iteratee(i, v)
@@ -433,9 +395,6 @@ func Map[T any, U any](slice []T, iteratee func(index int, item T) U) []U {
// Reduce creates an slice of values by running each element of slice thru iteratee function. // Reduce creates an slice of values by running each element of slice thru iteratee function.
func Reduce[T any](slice []T, iteratee func(index int, item1, item2 T) T, initial T) T { func Reduce[T any](slice []T, iteratee func(index int, item1, item2 T) T, initial T) T {
if iteratee == nil {
panic("iteratee func is missing")
}
if len(slice) == 0 { if len(slice) == 0 {
return initial return initial
@@ -604,12 +563,8 @@ func UpdateAt[T any](slice []T, index int, value T) []T {
// Unique remove duplicate elements in slice. // Unique remove duplicate elements in slice.
func Unique[T comparable](slice []T) []T { func Unique[T comparable](slice []T) []T {
if len(slice) == 0 { result := []T{}
return []T{}
}
// here no use map filter. if use it, the result slice element order is random, not same as origin slice
var result []T
for i := 0; i < len(slice); i++ { for i := 0; i < len(slice); i++ {
v := slice[i] v := slice[i]
skip := true skip := true
@@ -629,11 +584,8 @@ func Unique[T comparable](slice []T) []T {
// UniqueBy call iteratee func with every item of slice, then remove duplicated. // UniqueBy call iteratee func with every item of slice, then remove duplicated.
func UniqueBy[T comparable](slice []T, iteratee func(item T) T) []T { func UniqueBy[T comparable](slice []T, iteratee func(item T) T) []T {
if len(slice) == 0 { result := []T{}
return []T{}
}
var result []T
for _, v := range slice { for _, v := range slice {
val := iteratee(v) val := iteratee(v)
result = append(result, val) result = append(result, val)
@@ -642,20 +594,39 @@ func UniqueBy[T comparable](slice []T, iteratee func(item T) T) []T {
return Unique(result) return Unique(result)
} }
// Union creates a slice of unique values, in order, from all given slices. using == for equality comparisons. // Union creates a slice of unique values, in order, from all given slices.
func Union[T comparable](slices ...[]T) []T { func Union[T comparable](slices ...[]T) []T {
if len(slices) == 0 { result := []T{}
return []T{} contain := map[T]struct{}{}
}
// append all slices, then unique it
var allElements []T
for _, slice := range slices { for _, slice := range slices {
allElements = append(allElements, slice...) for _, item := range slice {
if _, ok := contain[item]; !ok {
contain[item] = struct{}{}
result = append(result, item)
}
}
} }
return Unique(allElements) return result
}
// UnionBy is like Union, what's more it accepts iteratee which is invoked for each element of each slice
func UnionBy[T any, V comparable](predicate func(item T) V, slices ...[]T) []T {
result := []T{}
contain := map[V]struct{}{}
for _, slice := range slices {
for _, item := range slice {
val := predicate(item)
if _, ok := contain[val]; !ok {
contain[val] = struct{}{}
result = append(result, item)
}
}
}
return result
} }
// Intersection creates a slice of unique values that included by all slices. // Intersection creates a slice of unique values that included by all slices.
@@ -667,8 +638,6 @@ func Intersection[T comparable](slices ...[]T) []T {
return Unique(slices[0]) return Unique(slices[0])
} }
var result []T
reducer := func(sliceA, sliceB []T) []T { reducer := func(sliceA, sliceB []T) []T {
hashMap := make(map[T]int) hashMap := make(map[T]int)
for _, val := range sliceA { for _, val := range sliceA {
@@ -685,7 +654,7 @@ func Intersection[T comparable](slices ...[]T) []T {
return out return out
} }
result = reducer(slices[0], slices[1]) result := reducer(slices[0], slices[1])
reduceSlice := make([][]T, 2) reduceSlice := make([][]T, 2)
for i := 2; i < len(slices); i++ { for i := 2; i < len(slices); i++ {
@@ -818,14 +787,14 @@ func Without[T comparable](slice []T, values ...T) []T {
return slice return slice
} }
out := make([]T, 0, len(slice)) result := make([]T, 0, len(slice))
for _, v := range slice { for _, v := range slice {
if !Contain(values, v) { if !Contain(values, v) {
out = append(out, v) result = append(result, v)
} }
} }
return out return result
} }
// IndexOf returns the index at which the first occurrence of a value is found in a slice or return -1 // IndexOf returns the index at which the first occurrence of a value is found in a slice or return -1
@@ -854,18 +823,20 @@ func LastIndexOf[T comparable](slice []T, value T) int {
// ToSlicePointer returns a pointer to the slices of a variable parameter transformation // ToSlicePointer returns a pointer to the slices of a variable parameter transformation
func ToSlicePointer[T any](value ...T) []*T { func ToSlicePointer[T any](value ...T) []*T {
out := make([]*T, len(value)) result := make([]*T, len(value))
for i := range value { for i := range value {
out[i] = &value[i] result[i] = &value[i]
} }
return out
return result
} }
// ToSlice returns a slices of a variable parameter transformation // ToSlice returns a slices of a variable parameter transformation
func ToSlice[T any](value ...T) []T { func ToSlice[T any](value ...T) []T {
out := make([]T, len(value)) result := make([]T, len(value))
copy(out, value) copy(result, value)
return out
return result
} }
// AppendIfAbsent only absent append the value // AppendIfAbsent only absent append the value
@@ -875,3 +846,15 @@ func AppendIfAbsent[T comparable](slice []T, value T) []T {
} }
return slice return slice
} }
// KeyBy converts a slice to a map based on a callback function
func KeyBy[T any, U comparable](slice []T, iteratee func(item T) U) map[U]T {
result := make(map[U]T, len(slice))
for _, v := range slice {
k := iteratee(v)
result[k] = v
}
return result
}

View File

@@ -428,6 +428,17 @@ func TestUnion(t *testing.T) {
assert.Equal([]int{1, 3, 4, 6}, Union(s1)) assert.Equal([]int{1, 3, 4, 6}, Union(s1))
} }
func TestUnionBy(t *testing.T) {
assert := internal.NewAssert(t, "TestUnionBy")
testFunc := func(i int) int {
return i / 2
}
result := UnionBy(testFunc, []int{0, 1, 2, 3, 4, 5}, []int{0, 2, 10})
assert.Equal(result, []int{0, 2, 4, 10})
}
func TestIntersection(t *testing.T) { func TestIntersection(t *testing.T) {
s1 := []int{1, 2, 2, 3} s1 := []int{1, 2, 2, 3}
s2 := []int{1, 2, 3, 4} s2 := []int{1, 2, 3, 4}
@@ -644,3 +655,13 @@ func TestReplaceAll(t *testing.T) {
assert.Equal([]string{"x", "b", "x", "c", "d", "x"}, ReplaceAll(strs, "a", "x")) assert.Equal([]string{"x", "b", "x", "c", "d", "x"}, ReplaceAll(strs, "a", "x"))
assert.Equal([]string{"a", "b", "a", "c", "d", "a"}, ReplaceAll(strs, "e", "x")) assert.Equal([]string{"a", "b", "a", "c", "d", "a"}, ReplaceAll(strs, "e", "x"))
} }
func TestKeyBy(t *testing.T) {
assert := internal.NewAssert(t, "TestKeyBy")
result := KeyBy([]string{"a", "ab", "abc"}, func(str string) int {
return len(str)
})
assert.Equal(result, map[int]string{1: "a", 2: "ab", 3: "abc"})
}