mirror of
https://github.com/duke-git/lancet.git
synced 2026-02-14 01:32:27 +08:00
Compare commits
3 Commits
v2.3.7
...
6f703fe577
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6f703fe577 | ||
|
|
cb8d93c499 | ||
|
|
ae1014c572 |
@@ -620,7 +620,7 @@ func main() {
|
|||||||
|
|
||||||
### <span id="Nand">Nand</span>
|
### <span id="Nand">Nand</span>
|
||||||
|
|
||||||
<p>Returns a composed predicate that represents the logical NAND of a list of predicates. It evaluates to true only if all predicates evaluate to false for the given value.</p>
|
<p>Returns a composed predicate that represents the logical NAND of a list of predicates. It evaluates to false only if all predicates evaluate to true for the given value.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
@@ -650,7 +650,7 @@ func main() {
|
|||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// false
|
// false
|
||||||
// false
|
// true
|
||||||
// true
|
// true
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ func And[T any](predicates ...func(T) bool) func(T) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Nand returns a composed predicate that represents the logical NAND of a list of predicates.
|
// Nand returns a composed predicate that represents the logical NAND of a list of predicates.
|
||||||
// It evaluates to true only if all predicates evaluate to false for the given value.
|
// It evaluates to false only if all predicates evaluate to true for the given value.
|
||||||
// Play: https://go.dev/play/p/Rb-FdNGpgSO
|
// Play: https://go.dev/play/p/Rb-FdNGpgSO
|
||||||
func Nand[T any](predicates ...func(T) bool) func(T) bool {
|
func Nand[T any](predicates ...func(T) bool) func(T) bool {
|
||||||
if len(predicates) < 2 {
|
if len(predicates) < 2 {
|
||||||
@@ -26,11 +26,11 @@ func Nand[T any](predicates ...func(T) bool) func(T) bool {
|
|||||||
}
|
}
|
||||||
return func(value T) bool {
|
return func(value T) bool {
|
||||||
for _, predicate := range predicates {
|
for _, predicate := range predicates {
|
||||||
if predicate(value) {
|
if !predicate(value) {
|
||||||
return false // Short-circuit on the first true predicate
|
return true // Short-circuit on the first false predicate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true // True if all predicates are false
|
return false // False if all predicates are true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ func ExampleNand() {
|
|||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// false
|
// false
|
||||||
// false
|
// true
|
||||||
// true
|
// true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ func TestPredicatesNandPure(t *testing.T) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
assert.ShouldBeFalse(isNumericAndLength5("12345"))
|
assert.ShouldBeFalse(isNumericAndLength5("12345"))
|
||||||
assert.ShouldBeFalse(isNumericAndLength5("1234"))
|
assert.ShouldBeTrue(isNumericAndLength5("1234"))
|
||||||
assert.ShouldBeTrue(isNumericAndLength5("abcdef"))
|
assert.ShouldBeTrue(isNumericAndLength5("abcdef"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -507,19 +507,17 @@ 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.
|
||||||
// Play: https://go.dev/play/p/DrPaa4YsHRF
|
|
||||||
func ForEach[T any](slice []T, iteratee func(index int, item T)) {
|
func ForEach[T any](slice []T, iteratee func(index int, item T)) {
|
||||||
for i := 0; i < len(slice); i++ {
|
for idx, elem := range slice {
|
||||||
iteratee(i, slice[i])
|
iteratee(idx, elem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ForEachWithBreak iterates over elements of slice and invokes function for each element,
|
// ForEachWithBreak iterates over elements of slice and invokes function for each element,
|
||||||
// when iteratee return false, will break the for each loop.
|
// when function return false, will break the for each loop.
|
||||||
// Play: https://go.dev/play/p/qScs39f3D9W
|
|
||||||
func ForEachWithBreak[T any](slice []T, iteratee func(index int, item T) bool) {
|
func ForEachWithBreak[T any](slice []T, iteratee func(index int, item T) bool) {
|
||||||
for i := 0; i < len(slice); i++ {
|
for idx, elem := range slice {
|
||||||
if !iteratee(i, slice[i]) {
|
if !iteratee(idx, elem) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1465,36 +1463,28 @@ func Random[T any](slice []T) (val T, idx int) {
|
|||||||
return slice[idx], idx
|
return slice[idx], idx
|
||||||
}
|
}
|
||||||
|
|
||||||
// RightPadding adds padding to the right end of a slice.
|
// RightPadding returns a copy of the slice padding the given value to the right end of a slice.
|
||||||
|
// If paddingLength is zero or less, the function returns a copy of the slice.
|
||||||
// Play: https://go.dev/play/p/0_2rlLEMBXL
|
// Play: https://go.dev/play/p/0_2rlLEMBXL
|
||||||
func RightPadding[T any](slice []T, paddingValue T, paddingLength int) []T {
|
func RightPadding[T any](slice []T, paddingValue T, paddingLength int) []T {
|
||||||
if paddingLength == 0 {
|
suffix := []T{}
|
||||||
return slice
|
if paddingLength > 0 {
|
||||||
|
suffix = repeat([]T{paddingValue}, paddingLength)
|
||||||
}
|
}
|
||||||
for i := 0; i < paddingLength; i++ {
|
padded := concat(slice, suffix)
|
||||||
slice = append(slice, paddingValue)
|
return padded
|
||||||
}
|
|
||||||
return slice
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// LeftPadding adds padding to the left begin of a slice.
|
// LeftPadding returns a copy of the slice padding the given value to the left begin of a slice.
|
||||||
|
// If paddingLength is zero or less, the function returns a copy of the slice.
|
||||||
// Play: https://go.dev/play/p/jlQVoelLl2k
|
// Play: https://go.dev/play/p/jlQVoelLl2k
|
||||||
func LeftPadding[T any](slice []T, paddingValue T, paddingLength int) []T {
|
func LeftPadding[T any](slice []T, paddingValue T, paddingLength int) []T {
|
||||||
if paddingLength == 0 {
|
prefix := []T{}
|
||||||
return slice
|
if paddingLength > 0 {
|
||||||
|
prefix = repeat([]T{paddingValue}, paddingLength)
|
||||||
}
|
}
|
||||||
|
padded := concat(prefix, slice)
|
||||||
paddedSlice := make([]T, len(slice)+paddingLength)
|
return padded
|
||||||
i := 0
|
|
||||||
for ; i < paddingLength; i++ {
|
|
||||||
paddedSlice[i] = paddingValue
|
|
||||||
}
|
|
||||||
for j := 0; j < len(slice); j++ {
|
|
||||||
paddedSlice[i] = slice[j]
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
|
|
||||||
return paddedSlice
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Frequency counts the frequency of each element in the slice.
|
// Frequency counts the frequency of each element in the slice.
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package slice
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math/bits"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"golang.org/x/exp/constraints"
|
"golang.org/x/exp/constraints"
|
||||||
@@ -96,3 +97,71 @@ func partitionAnySlice[T any](slice []T, lowIndex, highIndex int, less func(a, b
|
|||||||
func swap[T any](slice []T, i, j int) {
|
func swap[T any](slice []T, i, j int) {
|
||||||
slice[i], slice[j] = slice[j], slice[i]
|
slice[i], slice[j] = slice[j], slice[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// `repeat` returns a new slice that repeats the provided slice the given number of
|
||||||
|
// times. The result has length and capacity (len(x) * count). The result is never nil.
|
||||||
|
// Repeat panics if count is negative or if the result of (len(x) * count) overflows.
|
||||||
|
//
|
||||||
|
// repeat has been provided in the standard lib within the package `slices` under the
|
||||||
|
// name Repeat since GO version 1.21 onwards. As lancet commits to compatibility with GO
|
||||||
|
// 1.18 onwards, we implement the functionality as an internal function.
|
||||||
|
func repeat[S ~[]E, E any](x S, count int) S {
|
||||||
|
if count < 0 {
|
||||||
|
panic("count cannot be negative")
|
||||||
|
}
|
||||||
|
|
||||||
|
const maxInt = ^uint(0) >> 1
|
||||||
|
hi, lo := bits.Mul(uint(len(x)), uint(count))
|
||||||
|
if hi > 0 || lo > maxInt {
|
||||||
|
panic("the result of (len(x) * count) overflows")
|
||||||
|
}
|
||||||
|
|
||||||
|
newslice := make(S, int(lo)) // lo = len(x) * count
|
||||||
|
n := copy(newslice, x)
|
||||||
|
for n < len(newslice) {
|
||||||
|
n += copy(newslice[n:], newslice[:n])
|
||||||
|
}
|
||||||
|
return newslice
|
||||||
|
}
|
||||||
|
|
||||||
|
// concat returns a new slice concatenating the passed in slices.
|
||||||
|
//
|
||||||
|
// concat has been provided in the standard lib within the package `slices` under the
|
||||||
|
// name Concat since GO version 1.21 onwards. As lancet commits to compatibility with GO
|
||||||
|
// 1.18 onwards, we implement the functionality as an internal function.
|
||||||
|
func concat[S ~[]E, E any](slices ...S) S {
|
||||||
|
size := 0
|
||||||
|
for _, s := range slices {
|
||||||
|
size += len(s)
|
||||||
|
if size < 0 {
|
||||||
|
panic("len out of range")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Use Grow, not make, to round up to the size class:
|
||||||
|
// the extra space is otherwise unused and helps
|
||||||
|
// callers that append a few elements to the result.
|
||||||
|
newslice := grow[S](nil, size)
|
||||||
|
for _, s := range slices {
|
||||||
|
newslice = append(newslice, s...)
|
||||||
|
}
|
||||||
|
return newslice
|
||||||
|
}
|
||||||
|
|
||||||
|
// grow increases the slice's capacity, if necessary, to guarantee space for
|
||||||
|
// another n elements. After grow(n), at least n elements can be appended
|
||||||
|
// to the slice without another allocation. If n is negative or too large to
|
||||||
|
// allocate the memory, grow panics.
|
||||||
|
//
|
||||||
|
// grow has been provided in the standard lib within the package `slices` under the
|
||||||
|
// name Grow since GO version 1.21 onwards. As lancet commits to compatibility with GO
|
||||||
|
// 1.18 onwards, we implement the functionality as an internal function.
|
||||||
|
func grow[S ~[]E, E any](s S, n int) S {
|
||||||
|
if n < 0 {
|
||||||
|
panic("cannot be negative")
|
||||||
|
}
|
||||||
|
if n -= cap(s) - len(s); n > 0 {
|
||||||
|
// This expression allocates only once.
|
||||||
|
s = append(s[:cap(s)], make([]E, n)...)[:len(s)]
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|||||||
@@ -1756,6 +1756,20 @@ func TestRightPaddingAndLeftPadding(t *testing.T) {
|
|||||||
|
|
||||||
padded := LeftPadding(RightPadding(nums, 0, 3), 0, 3)
|
padded := LeftPadding(RightPadding(nums, 0, 3), 0, 3)
|
||||||
assert.Equal([]int{0, 0, 0, 1, 2, 3, 4, 5, 0, 0, 0}, padded)
|
assert.Equal([]int{0, 0, 0, 1, 2, 3, 4, 5, 0, 0, 0}, padded)
|
||||||
|
|
||||||
|
// Test with negative padding length
|
||||||
|
paddedNegative := LeftPadding(RightPadding(nums, 0, -3), 0, -3)
|
||||||
|
assert.Equal([]int{1, 2, 3, 4, 5}, paddedNegative)
|
||||||
|
|
||||||
|
// Test with empty slice
|
||||||
|
empty := []int{}
|
||||||
|
paddedEmpty := LeftPadding(RightPadding(empty, 0, 3), 0, 3)
|
||||||
|
assert.Equal([]int{0, 0, 0, 0, 0, 0}, paddedEmpty)
|
||||||
|
|
||||||
|
// Test with nil
|
||||||
|
nilSlice := []int(nil)
|
||||||
|
paddedNil := LeftPadding(RightPadding(nilSlice, 0, 3), 0, 3)
|
||||||
|
assert.Equal([]int{0, 0, 0, 0, 0, 0}, paddedNil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUniqueByConcurrent(t *testing.T) {
|
func TestUniqueByConcurrent(t *testing.T) {
|
||||||
|
|||||||
Reference in New Issue
Block a user