mirror of
https://github.com/duke-git/lancet.git
synced 2026-02-23 13:52:26 +08:00
Compare commits
12 Commits
v2.1.14
...
a7e77fa98d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a7e77fa98d | ||
|
|
abf392117a | ||
|
|
d231d9f572 | ||
|
|
97447d058e | ||
|
|
040e112aa6 | ||
|
|
afb021b4b5 | ||
|
|
5075774000 | ||
|
|
6bba44dc50 | ||
|
|
422022c74d | ||
|
|
87fcf97e2d | ||
|
|
05d1f348d4 | ||
|
|
6f2f1f3004 |
@@ -13,10 +13,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
NUMERAL = "0123456789"
|
Numeral = "0123456789"
|
||||||
LOWER_LETTERS = "abcdefghijklmnopqrstuvwxyz"
|
LowwerLetters = "abcdefghijklmnopqrstuvwxyz"
|
||||||
UPPER_LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
UpperLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
LETTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
Letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 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.
|
||||||
@@ -51,31 +51,31 @@ func RandBytes(length int) []byte {
|
|||||||
// RandString generate random string of specified length.
|
// RandString generate random string of specified length.
|
||||||
// Play: https://go.dev/play/p/W2xvRUXA7Mi
|
// Play: https://go.dev/play/p/W2xvRUXA7Mi
|
||||||
func RandString(length int) string {
|
func RandString(length int) string {
|
||||||
return random(LETTERS, length)
|
return random(Letters, length)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RandUpper generate a random upper case string.
|
// RandUpper generate a random upper case string.
|
||||||
// Play: https://go.dev/play/p/29QfOh0DVuh
|
// Play: https://go.dev/play/p/29QfOh0DVuh
|
||||||
func RandUpper(length int) string {
|
func RandUpper(length int) string {
|
||||||
return random(UPPER_LETTERS, length)
|
return random(UpperLetters, length)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RandLower generate a random lower case string.
|
// RandLower generate a random lower case string.
|
||||||
// Play: https://go.dev/play/p/XJtZ471cmtI
|
// Play: https://go.dev/play/p/XJtZ471cmtI
|
||||||
func RandLower(length int) string {
|
func RandLower(length int) string {
|
||||||
return random(LOWER_LETTERS, length)
|
return random(LowwerLetters, length)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RandNumeral generate a random numeral string of specified length.
|
// RandNumeral generate a random numeral string of specified length.
|
||||||
// Play: https://go.dev/play/p/g4JWVpHsJcf
|
// Play: https://go.dev/play/p/g4JWVpHsJcf
|
||||||
func RandNumeral(length int) string {
|
func RandNumeral(length int) string {
|
||||||
return random(NUMERAL, length)
|
return random(Numeral, length)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RandNumeralOrLetter generate a random numeral or letter string.
|
// RandNumeralOrLetter generate a random numeral or letter string.
|
||||||
// Play: https://go.dev/play/p/19CEQvpx2jD
|
// Play: https://go.dev/play/p/19CEQvpx2jD
|
||||||
func RandNumeralOrLetter(length int) string {
|
func RandNumeralOrLetter(length int) string {
|
||||||
return random(NUMERAL+LETTERS, length)
|
return random(Numeral+Letters, length)
|
||||||
}
|
}
|
||||||
|
|
||||||
// random generate a random string based on given string range.
|
// random generate a random string based on given string range.
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ package slice
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
@@ -559,24 +558,72 @@ func DeleteAt[T any](slice []T, start int, end ...int) []T {
|
|||||||
return slice
|
return slice
|
||||||
}
|
}
|
||||||
|
|
||||||
// Drop creates a slice with `n` elements dropped from the beginning when n > 0, or `n` elements dropped from the ending when n < 0.
|
// Drop drop n elements from the start of a slice.
|
||||||
// Play: https://go.dev/play/p/pJ-d6MUWcvK
|
// Play: https://go.dev/play/p/pJ-d6MUWcvK
|
||||||
func Drop[T any](slice []T, n int) []T {
|
func Drop[T any](slice []T, n int) []T {
|
||||||
size := len(slice)
|
size := len(slice)
|
||||||
|
|
||||||
if size == 0 || n == 0 {
|
if size <= n {
|
||||||
return slice
|
|
||||||
}
|
|
||||||
|
|
||||||
if math.Abs(float64(n)) >= float64(size) {
|
|
||||||
return []T{}
|
return []T{}
|
||||||
}
|
}
|
||||||
|
|
||||||
if n < 0 {
|
if n <= 0 {
|
||||||
return slice[0 : size+n]
|
return slice
|
||||||
}
|
}
|
||||||
|
|
||||||
return slice[n:size]
|
result := make([]T, 0, size-n)
|
||||||
|
|
||||||
|
return append(result, slice[n:]...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DropRight drop n elements from the end of a slice.
|
||||||
|
// Play: todo
|
||||||
|
func DropRight[T any](slice []T, n int) []T {
|
||||||
|
size := len(slice)
|
||||||
|
|
||||||
|
if size <= n {
|
||||||
|
return []T{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if n <= 0 {
|
||||||
|
return slice
|
||||||
|
}
|
||||||
|
|
||||||
|
result := make([]T, 0, size-n)
|
||||||
|
|
||||||
|
return append(result, slice[:size-n]...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DropWhile drop n elements from the start of a slice while predicate function returns true.
|
||||||
|
// Play: todo
|
||||||
|
func DropWhile[T any](slice []T, predicate func(item T) bool) []T {
|
||||||
|
i := 0
|
||||||
|
|
||||||
|
for ; i < len(slice); i++ {
|
||||||
|
if !predicate(slice[i]) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result := make([]T, 0, len(slice)-i)
|
||||||
|
|
||||||
|
return append(result, slice[i:]...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DropRightWhile drop n elements from the end of a slice while predicate function returns true.
|
||||||
|
// Play: todo
|
||||||
|
func DropRightWhile[T any](slice []T, predicate func(item T) bool) []T {
|
||||||
|
i := len(slice) - 1
|
||||||
|
|
||||||
|
for ; i >= 0; i-- {
|
||||||
|
if !predicate(slice[i]) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result := make([]T, 0, i+1)
|
||||||
|
|
||||||
|
return append(result, slice[:i+1]...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InsertAt insert the value or other slice into slice at index.
|
// InsertAt insert the value or other slice into slice at index.
|
||||||
@@ -783,6 +830,36 @@ func Shuffle[T any](slice []T) []T {
|
|||||||
return slice
|
return slice
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsAscending checks if a slice is ascending order.
|
||||||
|
// Play: todo
|
||||||
|
func IsAscending[T constraints.Ordered](slice []T) bool {
|
||||||
|
for i := 1; i < len(slice); i++ {
|
||||||
|
if slice[i-1] > slice[i] {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsDescending checks if a slice is descending order.
|
||||||
|
// Play: todo
|
||||||
|
func IsDescending[T constraints.Ordered](slice []T) bool {
|
||||||
|
for i := 1; i < len(slice); i++ {
|
||||||
|
if slice[i-1] < slice[i] {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsSorted checks if a slice is sorted(ascending or descending).
|
||||||
|
// Play: todo
|
||||||
|
func IsSorted[T constraints.Ordered](slice []T) bool {
|
||||||
|
return IsAscending(slice) || IsDescending(slice)
|
||||||
|
}
|
||||||
|
|
||||||
// Sort sorts a slice of any ordered type(number or string), use quick sort algrithm.
|
// Sort sorts a slice of any ordered type(number or string), use quick sort algrithm.
|
||||||
// default sort order is ascending (asc), if want descending order, set param `sortOrder` to `desc`.
|
// default sort order is ascending (asc), if want descending order, set param `sortOrder` to `desc`.
|
||||||
// Play: https://go.dev/play/p/V9AVjzf_4Fk
|
// Play: https://go.dev/play/p/V9AVjzf_4Fk
|
||||||
|
|||||||
@@ -482,10 +482,74 @@ func ExampleDrop() {
|
|||||||
// Output:
|
// Output:
|
||||||
// [a b c]
|
// [a b c]
|
||||||
// [b c]
|
// [b c]
|
||||||
// [a b]
|
// [a b c]
|
||||||
// []
|
// []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExampleDropRight() {
|
||||||
|
result1 := DropRight([]string{"a", "b", "c"}, 0)
|
||||||
|
result2 := DropRight([]string{"a", "b", "c"}, 1)
|
||||||
|
result3 := DropRight([]string{"a", "b", "c"}, -1)
|
||||||
|
result4 := DropRight([]string{"a", "b", "c"}, 4)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// [a b c]
|
||||||
|
// [a b]
|
||||||
|
// [a b c]
|
||||||
|
// []
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleDropWhile() {
|
||||||
|
numbers := []int{1, 2, 3, 4, 5}
|
||||||
|
|
||||||
|
result1 := DropWhile(numbers, func(n int) bool {
|
||||||
|
return n != 2
|
||||||
|
})
|
||||||
|
result2 := DropWhile(numbers, func(n int) bool {
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
result3 := DropWhile(numbers, func(n int) bool {
|
||||||
|
return n == 0
|
||||||
|
})
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// [2 3 4 5]
|
||||||
|
// []
|
||||||
|
// [1 2 3 4 5]
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleDropRightWhile() {
|
||||||
|
numbers := []int{1, 2, 3, 4, 5}
|
||||||
|
|
||||||
|
result1 := DropRightWhile(numbers, func(n int) bool {
|
||||||
|
return n != 2
|
||||||
|
})
|
||||||
|
result2 := DropRightWhile(numbers, func(n int) bool {
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
result3 := DropRightWhile(numbers, func(n int) bool {
|
||||||
|
return n == 0
|
||||||
|
})
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// [1 2]
|
||||||
|
// []
|
||||||
|
// [1 2 3 4 5]
|
||||||
|
}
|
||||||
|
|
||||||
func ExampleInsertAt() {
|
func ExampleInsertAt() {
|
||||||
result1 := InsertAt([]string{"a", "b", "c"}, 0, "1")
|
result1 := InsertAt([]string{"a", "b", "c"}, 0, "1")
|
||||||
result2 := InsertAt([]string{"a", "b", "c"}, 1, "1")
|
result2 := InsertAt([]string{"a", "b", "c"}, 1, "1")
|
||||||
@@ -621,6 +685,54 @@ func ExampleReverse() {
|
|||||||
// [d c b a]
|
// [d c b a]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExampleIsAscending() {
|
||||||
|
|
||||||
|
result1 := IsAscending([]int{1, 2, 3, 4, 5})
|
||||||
|
result2 := IsAscending([]int{5, 4, 3, 2, 1})
|
||||||
|
result3 := IsAscending([]int{2, 1, 3, 4, 5})
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleIsDescending() {
|
||||||
|
|
||||||
|
result1 := IsDescending([]int{5, 4, 3, 2, 1})
|
||||||
|
result2 := IsDescending([]int{1, 2, 3, 4, 5})
|
||||||
|
result3 := IsDescending([]int{2, 1, 3, 4, 5})
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleIsSorted() {
|
||||||
|
|
||||||
|
result1 := IsSorted([]int{1, 2, 3, 4, 5})
|
||||||
|
result2 := IsSorted([]int{5, 4, 3, 2, 1})
|
||||||
|
result3 := IsSorted([]int{2, 1, 3, 4, 5})
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
|
||||||
func ExampleSort() {
|
func ExampleSort() {
|
||||||
nums := []int{1, 4, 3, 2, 5}
|
nums := []int{1, 4, 3, 2, 5}
|
||||||
|
|
||||||
|
|||||||
@@ -377,7 +377,7 @@ func TestDeleteAt(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDrop(t *testing.T) {
|
func TestDrop(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestInterfaceSlice")
|
assert := internal.NewAssert(t, "TestDrop")
|
||||||
|
|
||||||
assert.Equal([]int{}, Drop([]int{}, 0))
|
assert.Equal([]int{}, Drop([]int{}, 0))
|
||||||
assert.Equal([]int{}, Drop([]int{}, 1))
|
assert.Equal([]int{}, Drop([]int{}, 1))
|
||||||
@@ -388,9 +388,64 @@ func TestDrop(t *testing.T) {
|
|||||||
assert.Equal([]int{}, Drop([]int{1, 2, 3, 4, 5}, 5))
|
assert.Equal([]int{}, Drop([]int{1, 2, 3, 4, 5}, 5))
|
||||||
assert.Equal([]int{}, Drop([]int{1, 2, 3, 4, 5}, 6))
|
assert.Equal([]int{}, Drop([]int{1, 2, 3, 4, 5}, 6))
|
||||||
|
|
||||||
assert.Equal([]int{1, 2, 3, 4}, Drop([]int{1, 2, 3, 4, 5}, -1))
|
assert.Equal([]int{1, 2, 3, 4, 5}, Drop([]int{1, 2, 3, 4, 5}, -1))
|
||||||
assert.Equal([]int{}, Drop([]int{1, 2, 3, 4, 5}, -6))
|
}
|
||||||
assert.Equal([]int{}, Drop([]int{1, 2, 3, 4, 5}, -6))
|
|
||||||
|
func TestDropRight(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestDropRight")
|
||||||
|
|
||||||
|
assert.Equal([]int{}, DropRight([]int{}, 0))
|
||||||
|
assert.Equal([]int{}, DropRight([]int{}, 1))
|
||||||
|
assert.Equal([]int{}, DropRight([]int{}, -1))
|
||||||
|
|
||||||
|
assert.Equal([]int{1, 2, 3, 4, 5}, DropRight([]int{1, 2, 3, 4, 5}, 0))
|
||||||
|
assert.Equal([]int{1, 2, 3, 4}, DropRight([]int{1, 2, 3, 4, 5}, 1))
|
||||||
|
assert.Equal([]int{}, DropRight([]int{1, 2, 3, 4, 5}, 5))
|
||||||
|
assert.Equal([]int{}, DropRight([]int{1, 2, 3, 4, 5}, 6))
|
||||||
|
|
||||||
|
assert.Equal([]int{1, 2, 3, 4, 5}, DropRight([]int{1, 2, 3, 4, 5}, -1))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDropWhile(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestDropWhile")
|
||||||
|
|
||||||
|
numbers := []int{1, 2, 3, 4, 5}
|
||||||
|
|
||||||
|
r1 := DropWhile(numbers, func(n int) bool {
|
||||||
|
return n != 2
|
||||||
|
})
|
||||||
|
assert.Equal([]int{2, 3, 4, 5}, r1)
|
||||||
|
|
||||||
|
r2 := DropWhile(numbers, func(n int) bool {
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
assert.Equal([]int{}, r2)
|
||||||
|
|
||||||
|
r3 := DropWhile(numbers, func(n int) bool {
|
||||||
|
return n == 0
|
||||||
|
})
|
||||||
|
assert.Equal([]int{1, 2, 3, 4, 5}, r3)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDropRightWhile(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestDropRightWhile")
|
||||||
|
|
||||||
|
numbers := []int{1, 2, 3, 4, 5}
|
||||||
|
|
||||||
|
r1 := DropRightWhile(numbers, func(n int) bool {
|
||||||
|
return n != 2
|
||||||
|
})
|
||||||
|
assert.Equal([]int{1, 2}, r1)
|
||||||
|
|
||||||
|
r2 := DropRightWhile(numbers, func(n int) bool {
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
assert.Equal([]int{}, r2)
|
||||||
|
|
||||||
|
r3 := DropRightWhile(numbers, func(n int) bool {
|
||||||
|
return n == 0
|
||||||
|
})
|
||||||
|
assert.Equal([]int{1, 2, 3, 4, 5}, r3)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInsertAt(t *testing.T) {
|
func TestInsertAt(t *testing.T) {
|
||||||
@@ -548,6 +603,30 @@ func TestDifferenceBy(t *testing.T) {
|
|||||||
assert.Equal([]int{1, 2}, DifferenceBy(s1, s2, addOne))
|
assert.Equal([]int{1, 2}, DifferenceBy(s1, s2, addOne))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIsAscending(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestIsAscending")
|
||||||
|
|
||||||
|
assert.Equal(true, IsAscending([]int{1, 2, 3, 4, 5}))
|
||||||
|
assert.Equal(false, IsAscending([]int{5, 4, 3, 2, 1}))
|
||||||
|
assert.Equal(false, IsAscending([]int{2, 1, 3, 4, 5}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsDescending(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestIsDescending")
|
||||||
|
|
||||||
|
assert.Equal(true, IsDescending([]int{5, 4, 3, 2, 1}))
|
||||||
|
assert.Equal(false, IsDescending([]int{1, 2, 3, 4, 5}))
|
||||||
|
assert.Equal(false, IsDescending([]int{2, 1, 3, 4, 5}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsSorted(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestIsSorted")
|
||||||
|
|
||||||
|
assert.Equal(true, IsSorted([]int{5, 4, 3, 2, 1}))
|
||||||
|
assert.Equal(true, IsSorted([]int{1, 2, 3, 4, 5}))
|
||||||
|
assert.Equal(false, IsSorted([]int{2, 1, 3, 4, 5}))
|
||||||
|
}
|
||||||
|
|
||||||
func TestSort(t *testing.T) {
|
func TestSort(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestSort")
|
assert := internal.NewAssert(t, "TestSort")
|
||||||
|
|
||||||
|
|||||||
113
stream/stream.go
113
stream/stream.go
@@ -10,6 +10,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"encoding/gob"
|
"encoding/gob"
|
||||||
|
|
||||||
|
"github.com/duke-git/lancet/v2/slice"
|
||||||
"golang.org/x/exp/constraints"
|
"golang.org/x/exp/constraints"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -23,7 +24,7 @@ import (
|
|||||||
// Map(mapper func(item T) T) StreamI[T]
|
// Map(mapper func(item T) T) StreamI[T]
|
||||||
// Peek(consumer func(item T)) StreamI[T]
|
// Peek(consumer func(item T)) StreamI[T]
|
||||||
|
|
||||||
// Sort(less func(a, b T) bool) StreamI[T]
|
// Sorted(less func(a, b T) bool) StreamI[T]
|
||||||
// Max(less func(a, b T) bool) (T, bool)
|
// Max(less func(a, b T) bool) (T, bool)
|
||||||
// Min(less func(a, b T) bool) (T, bool)
|
// Min(less func(a, b T) bool) (T, bool)
|
||||||
|
|
||||||
@@ -43,7 +44,7 @@ import (
|
|||||||
|
|
||||||
// // part of methods custom extension
|
// // part of methods custom extension
|
||||||
// Reverse() StreamI[T]
|
// Reverse() StreamI[T]
|
||||||
// Range(start, end int64) StreamI[T]
|
// Range(start, end int) StreamI[T]
|
||||||
// Concat(streams ...StreamI[T]) StreamI[T]
|
// Concat(streams ...StreamI[T]) StreamI[T]
|
||||||
// }
|
// }
|
||||||
|
|
||||||
@@ -72,12 +73,12 @@ func Generate[T any](generator func() func() (item T, ok bool)) stream[T] {
|
|||||||
return FromSlice(source)
|
return FromSlice(source)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FromSlice create stream from slice.
|
// FromSlice creates stream from slice.
|
||||||
func FromSlice[T any](source []T) stream[T] {
|
func FromSlice[T any](source []T) stream[T] {
|
||||||
return stream[T]{source: source}
|
return stream[T]{source: source}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FromChannel create stream from channel.
|
// FromChannel creates stream from channel.
|
||||||
func FromChannel[T any](source <-chan T) stream[T] {
|
func FromChannel[T any](source <-chan T) stream[T] {
|
||||||
s := make([]T, 0)
|
s := make([]T, 0)
|
||||||
|
|
||||||
@@ -88,7 +89,7 @@ func FromChannel[T any](source <-chan T) stream[T] {
|
|||||||
return FromSlice(s)
|
return FromSlice(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FromRange create a number stream from start to end. both start and end are included. [start, end]
|
// FromRange creates a number stream from start to end. both start and end are included. [start, end]
|
||||||
func FromRange[T constraints.Integer | constraints.Float](start, end, step T) stream[T] {
|
func FromRange[T constraints.Integer | constraints.Float](start, end, step T) stream[T] {
|
||||||
if end < start {
|
if end < start {
|
||||||
panic("stream.FromRange: param start should be before param end")
|
panic("stream.FromRange: param start should be before param end")
|
||||||
@@ -106,6 +107,16 @@ func FromRange[T constraints.Integer | constraints.Float](start, end, step T) st
|
|||||||
return FromSlice(source)
|
return FromSlice(source)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Concat creates a lazily concatenated stream whose elements are all the elements of the first stream followed by all the elements of the second stream.
|
||||||
|
func Concat[T any](a, b stream[T]) stream[T] {
|
||||||
|
source := make([]T, 0)
|
||||||
|
|
||||||
|
source = append(source, a.source...)
|
||||||
|
source = append(source, b.source...)
|
||||||
|
|
||||||
|
return FromSlice(source)
|
||||||
|
}
|
||||||
|
|
||||||
// Distinct returns a stream that removes the duplicated items.
|
// Distinct returns a stream that removes the duplicated items.
|
||||||
func (s stream[T]) Distinct() stream[T] {
|
func (s stream[T]) Distinct() stream[T] {
|
||||||
source := make([]T, 0)
|
source := make([]T, 0)
|
||||||
@@ -255,6 +266,98 @@ func (s stream[T]) Count() int {
|
|||||||
return len(s.source)
|
return len(s.source)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FindFirst returns the first element of this stream and true, or zero value and false if the stream is empty.
|
||||||
|
func (s stream[T]) FindFirst() (T, bool) {
|
||||||
|
var result T
|
||||||
|
|
||||||
|
if s.source == nil || len(s.source) == 0 {
|
||||||
|
return result, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.source[0], true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reverse returns a stream whose elements are reverse order of given stream.
|
||||||
|
func (s stream[T]) Reverse() stream[T] {
|
||||||
|
l := len(s.source)
|
||||||
|
source := make([]T, l)
|
||||||
|
|
||||||
|
for i := 0; i < l; i++ {
|
||||||
|
source[i] = s.source[l-1-i]
|
||||||
|
}
|
||||||
|
return FromSlice(source)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Range returns a stream whose elements are in the range from start(included) to end(excluded) original stream.
|
||||||
|
func (s stream[T]) Range(start, end int) stream[T] {
|
||||||
|
if start < 0 {
|
||||||
|
start = 0
|
||||||
|
}
|
||||||
|
if end < 0 {
|
||||||
|
end = 0
|
||||||
|
}
|
||||||
|
if start >= end {
|
||||||
|
return FromSlice([]T{})
|
||||||
|
}
|
||||||
|
|
||||||
|
source := make([]T, 0)
|
||||||
|
|
||||||
|
if end > len(s.source) {
|
||||||
|
end = len(s.source)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := start; i < end; i++ {
|
||||||
|
source = append(source, s.source[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
return FromSlice(source)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sorted returns a stream consisting of the elements of this stream, sorted according to the provided less function.
|
||||||
|
func (s stream[T]) Sorted(less func(a, b T) bool) stream[T] {
|
||||||
|
source := []T{}
|
||||||
|
source = append(source, s.source...)
|
||||||
|
|
||||||
|
slice.SortBy(source, less)
|
||||||
|
|
||||||
|
return FromSlice(source)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Max returns the maximum element of this stream according to the provided less function.
|
||||||
|
// less: a > b
|
||||||
|
func (s stream[T]) Max(less func(a, b T) bool) (T, bool) {
|
||||||
|
var max T
|
||||||
|
|
||||||
|
if len(s.source) == 0 {
|
||||||
|
return max, false
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, v := range s.source {
|
||||||
|
if less(v, max) || i == 0 {
|
||||||
|
max = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return max, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Min returns the minimum element of this stream according to the provided less function.
|
||||||
|
// less: a < b
|
||||||
|
func (s stream[T]) Min(less func(a, b T) bool) (T, bool) {
|
||||||
|
var min T
|
||||||
|
|
||||||
|
if len(s.source) == 0 {
|
||||||
|
return min, false
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, v := range s.source {
|
||||||
|
if less(v, min) || i == 0 {
|
||||||
|
min = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return min, true
|
||||||
|
}
|
||||||
|
|
||||||
// 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
|
||||||
|
|||||||
@@ -247,3 +247,92 @@ func TestStream_Reduce(t *testing.T) {
|
|||||||
|
|
||||||
assert.Equal(6, result)
|
assert.Equal(6, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestStream_FindFirst(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestStream_FindFirst")
|
||||||
|
|
||||||
|
stream := FromSlice([]int{1, 2, 3})
|
||||||
|
|
||||||
|
result, ok := stream.FindFirst()
|
||||||
|
|
||||||
|
assert.Equal(1, result)
|
||||||
|
assert.Equal(true, ok)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStream_Reverse(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestStream_Reverse")
|
||||||
|
|
||||||
|
s := FromSlice([]int{1, 2, 3})
|
||||||
|
|
||||||
|
rs := s.Reverse()
|
||||||
|
|
||||||
|
assert.Equal([]int{3, 2, 1}, rs.ToSlice())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStream_Range(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestStream_Range")
|
||||||
|
|
||||||
|
s := FromSlice([]int{1, 2, 3})
|
||||||
|
|
||||||
|
s1 := s.Range(-1, 0)
|
||||||
|
assert.Equal([]int{}, s1.ToSlice())
|
||||||
|
|
||||||
|
s2 := s.Range(0, -1)
|
||||||
|
assert.Equal([]int{}, s2.ToSlice())
|
||||||
|
|
||||||
|
s3 := s.Range(0, 0)
|
||||||
|
assert.Equal([]int{}, s3.ToSlice())
|
||||||
|
|
||||||
|
s4 := s.Range(1, 1)
|
||||||
|
assert.Equal([]int{}, s4.ToSlice())
|
||||||
|
|
||||||
|
s5 := s.Range(0, 1)
|
||||||
|
assert.Equal([]int{1}, s5.ToSlice())
|
||||||
|
|
||||||
|
s6 := s.Range(0, 4)
|
||||||
|
assert.Equal([]int{1, 2, 3}, s6.ToSlice())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStream_Concat(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestStream_Concat")
|
||||||
|
|
||||||
|
s1 := FromSlice([]int{1, 2, 3})
|
||||||
|
s2 := FromSlice([]int{4, 5, 6})
|
||||||
|
|
||||||
|
s := Concat(s1, s2)
|
||||||
|
|
||||||
|
assert.Equal([]int{1, 2, 3, 4, 5, 6}, s.ToSlice())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStream_Sorted(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestStream_Sorted")
|
||||||
|
|
||||||
|
s := FromSlice([]int{4, 2, 1, 3})
|
||||||
|
|
||||||
|
s1 := s.Sorted(func(a, b int) bool { return a < b })
|
||||||
|
|
||||||
|
assert.Equal([]int{4, 2, 1, 3}, s.ToSlice())
|
||||||
|
assert.Equal([]int{1, 2, 3, 4}, s1.ToSlice())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStream_Max(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestStream_Max")
|
||||||
|
|
||||||
|
s := FromSlice([]int{4, 2, 1, 3})
|
||||||
|
|
||||||
|
max, ok := s.Max(func(a, b int) bool { return a > b })
|
||||||
|
|
||||||
|
assert.Equal(4, max)
|
||||||
|
assert.Equal(true, ok)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStream_Min(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestStream_Min")
|
||||||
|
|
||||||
|
s := FromSlice([]int{4, 2, 1, 3})
|
||||||
|
|
||||||
|
max, ok := s.Max(func(a, b int) bool { return a < b })
|
||||||
|
|
||||||
|
assert.Equal(1, max)
|
||||||
|
assert.Equal(true, ok)
|
||||||
|
}
|
||||||
|
|||||||
@@ -281,6 +281,10 @@ func IsZeroValue(value any) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
rv := reflect.ValueOf(value)
|
rv := reflect.ValueOf(value)
|
||||||
|
if rv.Kind() == reflect.Ptr {
|
||||||
|
rv = rv.Elem()
|
||||||
|
}
|
||||||
|
|
||||||
if !rv.IsValid() {
|
if !rv.IsValid() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user