mirror of
https://github.com/duke-git/lancet.git
synced 2026-02-13 17:22:27 +08:00
Compare commits
4 Commits
3e8c3bd396
...
ec092a009a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ec092a009a | ||
|
|
ca40b5d6c6 | ||
|
|
a6d39a3bba | ||
|
|
38148978cf |
@@ -56,7 +56,7 @@ import (
|
||||
- [ConcurrentMap_Has](#ConcurrentMap_Has)
|
||||
- [ConcurrentMap_Range](#ConcurrentMap_Range)
|
||||
- [GetOrSet](#GetOrSet)
|
||||
- [SortByKeys](#SortByKeys)
|
||||
- [SortByKey](#SortByKey)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
@@ -1525,14 +1525,14 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="SortByKeys">SortByKeys</span>
|
||||
### <span id="SortByKey">SortByKey</span>
|
||||
|
||||
<p>对传入的map根据key进行排序,返回排序后的map。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func SortByKeys[K constraints.Ordered, V any](m map[K]V) (sortedKeysMap map[K]V)
|
||||
func SortByKey[K constraints.Ordered, V any](m map[K]V) (sortedKeysMap map[K]V)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
@@ -1553,7 +1553,7 @@ func main() {
|
||||
2: "b",
|
||||
}
|
||||
|
||||
result := maputil.SortByKeys(m)
|
||||
result := maputil.SortByKey(m)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
|
||||
@@ -1540,14 +1540,14 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="SortByKeys">SortByKeys</span>
|
||||
### <span id="SortByKey">SortByKey</span>
|
||||
|
||||
<p>Sorts the map by its keys and returns a new map with sorted keys.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func SortByKeys[K constraints.Ordered, V any](m map[K]V) (sortedKeysMap map[K]V)
|
||||
func SortByKey[K constraints.Ordered, V any](m map[K]V) (sortedKeysMap map[K]V)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
@@ -1568,7 +1568,7 @@ func main() {
|
||||
2: "b",
|
||||
}
|
||||
|
||||
result := maputil.SortByKeys(m)
|
||||
result := maputil.SortByKey(m)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
|
||||
@@ -18,63 +18,63 @@ import (
|
||||
// http://en.wikipedia.org/wiki/Binary_prefix
|
||||
const (
|
||||
// Decimal
|
||||
UnitB = 1
|
||||
UnitKB = 1000
|
||||
UnitMB = 1000 * UnitKB
|
||||
UnitGB = 1000 * UnitMB
|
||||
UnitTB = 1000 * UnitGB
|
||||
UnitPB = 1000 * UnitTB
|
||||
UnitEB = 1000 * UnitPB
|
||||
unitB = 1
|
||||
unitKB = 1000
|
||||
unitMB = 1000 * unitKB
|
||||
unitGB = 1000 * unitMB
|
||||
unitTB = 1000 * unitGB
|
||||
unitPB = 1000 * unitTB
|
||||
unitEB = 1000 * unitPB
|
||||
|
||||
// Binary
|
||||
UnitBiB = 1
|
||||
UnitKiB = 1024
|
||||
UnitMiB = 1024 * UnitKiB
|
||||
UnitGiB = 1024 * UnitMiB
|
||||
UnitTiB = 1024 * UnitGiB
|
||||
UnitPiB = 1024 * UnitTiB
|
||||
UnitEiB = 1024 * UnitPiB
|
||||
unitBiB = 1
|
||||
unitKiB = 1024
|
||||
unitMiB = 1024 * unitKiB
|
||||
unitGiB = 1024 * unitMiB
|
||||
unitTiB = 1024 * unitGiB
|
||||
unitPiB = 1024 * unitTiB
|
||||
unitEiB = 1024 * unitPiB
|
||||
)
|
||||
|
||||
// type byteUnitMap map[byte]int64
|
||||
|
||||
var (
|
||||
decimalByteMap = map[string]uint64{
|
||||
"b": UnitB,
|
||||
"kb": UnitKB,
|
||||
"mb": UnitMB,
|
||||
"gb": UnitGB,
|
||||
"tb": UnitTB,
|
||||
"pb": UnitPB,
|
||||
"eb": UnitEB,
|
||||
"b": unitB,
|
||||
"kb": unitKB,
|
||||
"mb": unitMB,
|
||||
"gb": unitGB,
|
||||
"tb": unitTB,
|
||||
"pb": unitPB,
|
||||
"eb": unitEB,
|
||||
|
||||
// Without suffix
|
||||
"": UnitB,
|
||||
"k": UnitKB,
|
||||
"m": UnitMB,
|
||||
"g": UnitGB,
|
||||
"t": UnitTB,
|
||||
"p": UnitPB,
|
||||
"e": UnitEB,
|
||||
"": unitB,
|
||||
"k": unitKB,
|
||||
"m": unitMB,
|
||||
"g": unitGB,
|
||||
"t": unitTB,
|
||||
"p": unitPB,
|
||||
"e": unitEB,
|
||||
}
|
||||
|
||||
binaryByteMap = map[string]uint64{
|
||||
"bi": UnitBiB,
|
||||
"kib": UnitKiB,
|
||||
"mib": UnitMiB,
|
||||
"gib": UnitGiB,
|
||||
"tib": UnitTiB,
|
||||
"pib": UnitPiB,
|
||||
"eib": UnitEiB,
|
||||
"bi": unitBiB,
|
||||
"kib": unitKiB,
|
||||
"mib": unitMiB,
|
||||
"gib": unitGiB,
|
||||
"tib": unitTiB,
|
||||
"pib": unitPiB,
|
||||
"eib": unitEiB,
|
||||
|
||||
// Without suffix
|
||||
"": UnitBiB,
|
||||
"ki": UnitKiB,
|
||||
"mi": UnitMiB,
|
||||
"gi": UnitGiB,
|
||||
"ti": UnitTiB,
|
||||
"pi": UnitPiB,
|
||||
"ei": UnitEiB,
|
||||
"": unitBiB,
|
||||
"ki": unitKiB,
|
||||
"mi": unitMiB,
|
||||
"gi": unitGiB,
|
||||
"ti": unitTiB,
|
||||
"pi": unitPiB,
|
||||
"ei": unitEiB,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -15,11 +15,11 @@ func TestDecimalBytes(t *testing.T) {
|
||||
assert.Equal("1.024KB", DecimalBytes(1024))
|
||||
assert.Equal("1.2346MB", DecimalBytes(1234567))
|
||||
assert.Equal("1.235MB", DecimalBytes(1234567, 3))
|
||||
assert.Equal("1.123GB", DecimalBytes(float64(1.123*UnitGB)))
|
||||
assert.Equal("2.123TB", DecimalBytes(float64(2.123*UnitTB)))
|
||||
assert.Equal("3.123PB", DecimalBytes(float64(3.123*UnitPB)))
|
||||
assert.Equal("4.123EB", DecimalBytes(float64(4.123*UnitEB)))
|
||||
assert.Equal("1EB", DecimalBytes(float64(1000*UnitPB)))
|
||||
assert.Equal("1.123GB", DecimalBytes(float64(1.123*unitGB)))
|
||||
assert.Equal("2.123TB", DecimalBytes(float64(2.123*unitTB)))
|
||||
assert.Equal("3.123PB", DecimalBytes(float64(3.123*unitPB)))
|
||||
assert.Equal("4.123EB", DecimalBytes(float64(4.123*unitEB)))
|
||||
assert.Equal("1EB", DecimalBytes(float64(1000*unitPB)))
|
||||
assert.Equal("62MB", DecimalBytes(61812496, 0))
|
||||
assert.Equal("61.8MB", DecimalBytes(61812496, 1))
|
||||
assert.Equal("401MB", DecimalBytes(401000000))
|
||||
|
||||
@@ -454,16 +454,16 @@ func GetOrSet[K comparable, V any](m map[K]V, key K, value V) V {
|
||||
return value
|
||||
}
|
||||
|
||||
// SortByKeys sorts the map by its keys and returns a new map with sorted keys.
|
||||
// SortByKey sorts the map by its keys and returns a new map with sorted keys.
|
||||
// Play: todo
|
||||
func SortByKeys[K constraints.Ordered, V any](m map[K]V) (sortedKeysMap map[K]V) {
|
||||
func SortByKey[K constraints.Ordered, V any](m map[K]V, less func(a, b K) bool) (sortedKeysMap map[K]V) {
|
||||
keys := make([]K, 0, len(m))
|
||||
for k := range m {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
|
||||
sort.Slice(keys, func(i, j int) bool {
|
||||
return keys[i] < keys[j]
|
||||
return less(keys[i], keys[j])
|
||||
})
|
||||
|
||||
sortedKeysMap = make(map[K]V, len(m))
|
||||
|
||||
@@ -541,7 +541,7 @@ func ExampleGetOrSet() {
|
||||
// b
|
||||
}
|
||||
|
||||
func ExampleSortByKeys() {
|
||||
func ExampleSortByKey() {
|
||||
m := map[int]string{
|
||||
3: "c",
|
||||
1: "a",
|
||||
@@ -549,7 +549,9 @@ func ExampleSortByKeys() {
|
||||
2: "b",
|
||||
}
|
||||
|
||||
result := SortByKeys(m)
|
||||
result := SortByKey(m, func(a, b int) bool {
|
||||
return a < b
|
||||
})
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
|
||||
@@ -708,10 +708,10 @@ func TestGetOrSet(t *testing.T) {
|
||||
assert.Equal("b", result2)
|
||||
}
|
||||
|
||||
func TestSortByKeys(t *testing.T) {
|
||||
func TestSortByKey(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestSortByKeys")
|
||||
assert := internal.NewAssert(t, "TestSortByKey")
|
||||
|
||||
m1 := map[int]string{
|
||||
3: "c",
|
||||
@@ -726,7 +726,9 @@ func TestSortByKeys(t *testing.T) {
|
||||
4: "d",
|
||||
}
|
||||
|
||||
result1 := SortByKeys(m1)
|
||||
result1 := SortByKey(m1, func(a, b int) bool {
|
||||
return a < b
|
||||
})
|
||||
|
||||
assert.Equal(expected1, result1)
|
||||
|
||||
@@ -737,13 +739,15 @@ func TestSortByKeys(t *testing.T) {
|
||||
"b": 2,
|
||||
}
|
||||
expected2 := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
"d": 4,
|
||||
"c": 3,
|
||||
"b": 2,
|
||||
"a": 1,
|
||||
}
|
||||
|
||||
result2 := SortByKeys(m2)
|
||||
result2 := SortByKey(m2, func(a, b string) bool {
|
||||
return a > b
|
||||
})
|
||||
|
||||
assert.Equal(expected2, result2)
|
||||
}
|
||||
|
||||
431
maputil/orderedmap.go
Normal file
431
maputil/orderedmap.go
Normal file
@@ -0,0 +1,431 @@
|
||||
package maputil
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// OrderedMap is a map that maintains the order of keys.
|
||||
type OrderedMap[K comparable, V any] struct {
|
||||
mu sync.RWMutex
|
||||
|
||||
data map[K]V
|
||||
order *list.List
|
||||
index map[K]*list.Element
|
||||
}
|
||||
|
||||
// NewOrderedMap creates a new OrderedMap.
|
||||
func NewOrderedMap[K comparable, V any]() *OrderedMap[K, V] {
|
||||
return &OrderedMap[K, V]{
|
||||
data: make(map[K]V),
|
||||
order: list.New(),
|
||||
index: make(map[K]*list.Element),
|
||||
}
|
||||
}
|
||||
|
||||
// Get returns the value for the given key.
|
||||
// Play: todo
|
||||
func (om *OrderedMap[K, V]) Set(key K, value V) {
|
||||
om.mu.Lock()
|
||||
defer om.mu.Unlock()
|
||||
|
||||
if elem, ok := om.index[key]; ok {
|
||||
elem.Value = value
|
||||
om.order.MoveToBack(elem)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
om.data[key] = value
|
||||
|
||||
elem := om.order.PushBack(key)
|
||||
om.index[key] = elem
|
||||
}
|
||||
|
||||
// Get returns the value for the given key.
|
||||
// Play: todo
|
||||
func (om *OrderedMap[K, V]) Get(key K) (V, bool) {
|
||||
om.mu.RLock()
|
||||
defer om.mu.RUnlock()
|
||||
|
||||
value, ok := om.data[key]
|
||||
|
||||
return value, ok
|
||||
}
|
||||
|
||||
// Delete deletes the given key.
|
||||
// Play: todo
|
||||
func (om *OrderedMap[K, V]) Delete(key K) {
|
||||
om.mu.Lock()
|
||||
defer om.mu.Unlock()
|
||||
|
||||
if elem, ok := om.index[key]; ok {
|
||||
om.order.Remove(elem)
|
||||
delete(om.data, key)
|
||||
delete(om.index, key)
|
||||
}
|
||||
}
|
||||
|
||||
// Clear clears the map.
|
||||
// Play: todo
|
||||
func (om *OrderedMap[K, V]) Clear() {
|
||||
om.mu.Lock()
|
||||
defer om.mu.Unlock()
|
||||
|
||||
om.data = make(map[K]V)
|
||||
om.order.Init()
|
||||
om.index = make(map[K]*list.Element)
|
||||
}
|
||||
|
||||
// Front returns the first key-value pair.
|
||||
// Play: todo
|
||||
func (om *OrderedMap[K, V]) Front() (struct {
|
||||
Key K
|
||||
Value V
|
||||
}, bool) {
|
||||
om.mu.RLock()
|
||||
defer om.mu.RUnlock()
|
||||
|
||||
if elem := om.order.Front(); elem != nil {
|
||||
key := elem.Value.(K)
|
||||
value := om.data[key]
|
||||
|
||||
return struct {
|
||||
Key K
|
||||
Value V
|
||||
}{
|
||||
Key: key,
|
||||
Value: value,
|
||||
}, true
|
||||
}
|
||||
|
||||
return struct {
|
||||
Key K
|
||||
Value V
|
||||
}{}, false
|
||||
}
|
||||
|
||||
// Back returns the last key-value pair.
|
||||
// Play: todo
|
||||
func (om *OrderedMap[K, V]) Back() (struct {
|
||||
Key K
|
||||
Value V
|
||||
}, bool) {
|
||||
om.mu.RLock()
|
||||
defer om.mu.RUnlock()
|
||||
|
||||
if elem := om.order.Back(); elem != nil {
|
||||
key := elem.Value.(K)
|
||||
value := om.data[key]
|
||||
|
||||
return struct {
|
||||
Key K
|
||||
Value V
|
||||
}{
|
||||
Key: key,
|
||||
Value: value,
|
||||
}, true
|
||||
}
|
||||
|
||||
return struct {
|
||||
Key K
|
||||
Value V
|
||||
}{}, false
|
||||
}
|
||||
|
||||
// Range calls the given function for each key-value pair.
|
||||
// Play: todo
|
||||
func (om *OrderedMap[K, V]) Range(iteratee func(key K, value V) bool) {
|
||||
om.mu.RLock()
|
||||
defer om.mu.RUnlock()
|
||||
|
||||
for elem := om.order.Front(); elem != nil; elem = elem.Next() {
|
||||
key := elem.Value.(K)
|
||||
value := om.data[key]
|
||||
|
||||
if !iteratee(key, value) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Keys returns the keys in order.
|
||||
// Play: todo
|
||||
func (om *OrderedMap[K, V]) Keys() []K {
|
||||
om.mu.RLock()
|
||||
defer om.mu.RUnlock()
|
||||
|
||||
keys := make([]K, 0, len(om.data))
|
||||
|
||||
for elem := om.order.Front(); elem != nil; elem = elem.Next() {
|
||||
keys = append(keys, elem.Value.(K))
|
||||
}
|
||||
|
||||
return keys
|
||||
}
|
||||
|
||||
// Values returns the values in order.
|
||||
// Play: todo
|
||||
func (om *OrderedMap[K, V]) Values() []V {
|
||||
om.mu.RLock()
|
||||
defer om.mu.RUnlock()
|
||||
|
||||
values := make([]V, 0, len(om.data))
|
||||
|
||||
for elem := om.order.Front(); elem != nil; elem = elem.Next() {
|
||||
key := elem.Value.(K)
|
||||
values = append(values, om.data[key])
|
||||
}
|
||||
|
||||
return values
|
||||
}
|
||||
|
||||
// Len returns the number of key-value pairs.
|
||||
// Play: todo
|
||||
func (om *OrderedMap[K, V]) Len() int {
|
||||
om.mu.RLock()
|
||||
defer om.mu.RUnlock()
|
||||
|
||||
return len(om.data)
|
||||
}
|
||||
|
||||
// Contains returns true if the given key exists.
|
||||
// Play: todo
|
||||
func (om *OrderedMap[K, V]) Contains(key K) bool {
|
||||
om.mu.RLock()
|
||||
defer om.mu.RUnlock()
|
||||
|
||||
_, ok := om.data[key]
|
||||
|
||||
return ok
|
||||
}
|
||||
|
||||
// Elements returns the key-value pairs in order.
|
||||
// Play: todo
|
||||
func (om *OrderedMap[K, V]) Elements() []struct {
|
||||
Key K
|
||||
Value V
|
||||
} {
|
||||
om.mu.RLock()
|
||||
defer om.mu.RUnlock()
|
||||
|
||||
elements := make([]struct {
|
||||
Key K
|
||||
Value V
|
||||
}, 0, len(om.data))
|
||||
|
||||
for elem := om.order.Front(); elem != nil; elem = elem.Next() {
|
||||
key := elem.Value.(K)
|
||||
value := om.data[key]
|
||||
elements = append(elements, struct {
|
||||
Key K
|
||||
Value V
|
||||
}{Key: key, Value: value})
|
||||
}
|
||||
|
||||
return elements
|
||||
}
|
||||
|
||||
// Iter returns a channel that yields key-value pairs in order.
|
||||
// Play: todo
|
||||
func (om *OrderedMap[K, V]) Iter() <-chan struct {
|
||||
Key K
|
||||
Value V
|
||||
} {
|
||||
ch := make(chan struct {
|
||||
Key K
|
||||
Value V
|
||||
})
|
||||
|
||||
go func() {
|
||||
om.mu.RLock()
|
||||
defer om.mu.RUnlock()
|
||||
defer close(ch)
|
||||
|
||||
for elem := om.order.Front(); elem != nil; elem = elem.Next() {
|
||||
key := elem.Value.(K)
|
||||
value := om.data[key]
|
||||
|
||||
ch <- struct {
|
||||
Key K
|
||||
Value V
|
||||
}{Key: key, Value: value}
|
||||
}
|
||||
}()
|
||||
|
||||
return ch
|
||||
}
|
||||
|
||||
// ReverseIter returns a channel that yields key-value pairs in reverse order.
|
||||
// Play: todo
|
||||
func (om *OrderedMap[K, V]) ReverseIter() <-chan struct {
|
||||
Key K
|
||||
Value V
|
||||
} {
|
||||
ch := make(chan struct {
|
||||
Key K
|
||||
Value V
|
||||
})
|
||||
|
||||
go func() {
|
||||
om.mu.RLock()
|
||||
defer om.mu.RUnlock()
|
||||
defer close(ch)
|
||||
|
||||
for elem := om.order.Back(); elem != nil; elem = elem.Prev() {
|
||||
key := elem.Value.(K)
|
||||
value := om.data[key]
|
||||
|
||||
ch <- struct {
|
||||
Key K
|
||||
Value V
|
||||
}{Key: key, Value: value}
|
||||
}
|
||||
}()
|
||||
|
||||
return ch
|
||||
}
|
||||
|
||||
// SortByValue sorts the map by key given less function.
|
||||
// Play: todo
|
||||
func (om *OrderedMap[K, V]) SortByKey(less func(a, b K) bool) {
|
||||
om.mu.Lock()
|
||||
defer om.mu.Unlock()
|
||||
|
||||
keys := make([]K, 0, om.order.Len())
|
||||
for elem := om.order.Front(); elem != nil; elem = elem.Next() {
|
||||
keys = append(keys, elem.Value.(K))
|
||||
}
|
||||
|
||||
sort.Slice(keys, func(i, j int) bool {
|
||||
return less(keys[i], keys[j])
|
||||
})
|
||||
|
||||
om.order.Init()
|
||||
om.index = make(map[K]*list.Element)
|
||||
for _, key := range keys {
|
||||
elem := om.order.PushBack(key)
|
||||
om.index[key] = elem
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface.
|
||||
// Play: todo
|
||||
func (om *OrderedMap[K, V]) MarshalJSON() ([]byte, error) {
|
||||
om.mu.RLock()
|
||||
defer om.mu.RUnlock()
|
||||
|
||||
tempMap := make(map[string]V)
|
||||
for e := om.order.Front(); e != nil; e = e.Next() {
|
||||
key := e.Value.(K)
|
||||
keyStr, err := keyToString(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tempMap[keyStr] = om.data[key]
|
||||
}
|
||||
|
||||
return json.Marshal(tempMap)
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the json.Unmarshaler interface.
|
||||
// Play: todo
|
||||
func (om *OrderedMap[K, V]) UnmarshalJSON(data []byte) error {
|
||||
om.mu.Lock()
|
||||
defer om.mu.Unlock()
|
||||
|
||||
tempMap := make(map[string]V)
|
||||
if err := json.Unmarshal(data, &tempMap); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
om.data = make(map[K]V)
|
||||
om.order.Init()
|
||||
om.index = make(map[K]*list.Element)
|
||||
|
||||
for keyStr, value := range tempMap {
|
||||
key, err := stringToKey[K](keyStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
om.data[key] = value
|
||||
elem := om.order.PushBack(key)
|
||||
om.index[key] = elem
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func keyToString[K any](key K) (string, error) {
|
||||
switch v := any(key).(type) {
|
||||
case int:
|
||||
return strconv.Itoa(v), nil
|
||||
case float64:
|
||||
return strconv.FormatFloat(v, 'f', -1, 64), nil
|
||||
case string:
|
||||
return v, nil
|
||||
default:
|
||||
// 使用反射将未知类型转换为字符串
|
||||
rv := reflect.ValueOf(key)
|
||||
switch rv.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return strconv.FormatInt(rv.Int(), 10), nil
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return strconv.FormatUint(rv.Uint(), 10), nil
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return strconv.FormatFloat(rv.Float(), 'f', -1, 64), nil
|
||||
case reflect.String:
|
||||
return rv.String(), nil
|
||||
default:
|
||||
return "", fmt.Errorf("unsupported key type: %T", key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func stringToKey[K any](s string) (K, error) {
|
||||
var zero K
|
||||
switch any(zero).(type) {
|
||||
case int:
|
||||
value, err := strconv.Atoi(s)
|
||||
return any(value).(K), err
|
||||
case float64:
|
||||
value, err := strconv.ParseFloat(s, 64)
|
||||
return any(value).(K), err
|
||||
case string:
|
||||
return any(s).(K), nil
|
||||
default:
|
||||
// 使用反射恢复未知类型的键
|
||||
rv := reflect.ValueOf(&zero).Elem()
|
||||
switch rv.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
val, err := strconv.ParseInt(s, 10, 64)
|
||||
if err != nil {
|
||||
return zero, err
|
||||
}
|
||||
rv.SetInt(val)
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
val, err := strconv.ParseUint(s, 10, 64)
|
||||
if err != nil {
|
||||
return zero, err
|
||||
}
|
||||
rv.SetUint(val)
|
||||
case reflect.Float32, reflect.Float64:
|
||||
val, err := strconv.ParseFloat(s, 64)
|
||||
if err != nil {
|
||||
return zero, err
|
||||
}
|
||||
rv.SetFloat(val)
|
||||
case reflect.String:
|
||||
rv.SetString(s)
|
||||
default:
|
||||
return zero, fmt.Errorf("unsupported key type: %T", zero)
|
||||
}
|
||||
|
||||
return rv.Interface().(K), nil
|
||||
}
|
||||
}
|
||||
245
maputil/orderedmap_test.go
Normal file
245
maputil/orderedmap_test.go
Normal file
@@ -0,0 +1,245 @@
|
||||
package maputil
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestOrderedMap_Set_Get(t *testing.T) {
|
||||
om := NewOrderedMap[string, int]()
|
||||
|
||||
om.Set("a", 1)
|
||||
om.Set("b", 2)
|
||||
om.Set("c", 3)
|
||||
|
||||
assert := internal.NewAssert(t, "TestOrderedMap_Set_Get")
|
||||
|
||||
val, ok := om.Get("a")
|
||||
assert.Equal(1, val)
|
||||
assert.Equal(true, ok)
|
||||
|
||||
val, ok = om.Get("d")
|
||||
assert.Equal(false, ok)
|
||||
assert.Equal(0, val)
|
||||
}
|
||||
|
||||
func TestOrderedMap_Front_Back(t *testing.T) {
|
||||
om := NewOrderedMap[string, int]()
|
||||
|
||||
om.Set("a", 1)
|
||||
om.Set("b", 2)
|
||||
om.Set("c", 3)
|
||||
|
||||
assert := internal.NewAssert(t, "TestOrderedMap_Front_Back")
|
||||
|
||||
frontElement, ok := om.Front()
|
||||
assert.Equal("a", frontElement.Key)
|
||||
assert.Equal(1, frontElement.Value)
|
||||
assert.Equal(true, ok)
|
||||
|
||||
backElement, ok := om.Back()
|
||||
assert.Equal("c", backElement.Key)
|
||||
assert.Equal(3, backElement.Value)
|
||||
assert.Equal(true, ok)
|
||||
}
|
||||
|
||||
func TestOrderedMap_Delete_Clear(t *testing.T) {
|
||||
om := NewOrderedMap[string, int]()
|
||||
|
||||
om.Set("a", 1)
|
||||
om.Set("b", 2)
|
||||
om.Set("c", 3)
|
||||
|
||||
assert := internal.NewAssert(t, "TestOrderedMap_Delete_Clear")
|
||||
|
||||
assert.Equal(3, om.Len())
|
||||
|
||||
om.Delete("b")
|
||||
assert.Equal(2, om.Len())
|
||||
|
||||
om.Clear()
|
||||
assert.Equal(0, om.Len())
|
||||
}
|
||||
|
||||
func TestOrderedMap_Keys_Values(t *testing.T) {
|
||||
om := NewOrderedMap[string, int]()
|
||||
|
||||
om.Set("a", 1)
|
||||
om.Set("b", 2)
|
||||
om.Set("c", 3)
|
||||
|
||||
assert := internal.NewAssert(t, "TestOrderedMap_Keys_Values")
|
||||
|
||||
assert.Equal([]string{"a", "b", "c"}, om.Keys())
|
||||
assert.Equal([]int{1, 2, 3}, om.Values())
|
||||
}
|
||||
|
||||
func TestOrderedMap_Contains(t *testing.T) {
|
||||
om := NewOrderedMap[string, int]()
|
||||
|
||||
om.Set("a", 1)
|
||||
om.Set("b", 2)
|
||||
om.Set("c", 3)
|
||||
|
||||
assert := internal.NewAssert(t, "TestOrderedMap_Contains")
|
||||
|
||||
assert.Equal(true, om.Contains("a"))
|
||||
assert.Equal(false, om.Contains("d"))
|
||||
}
|
||||
|
||||
func TestOrderedMap_Eelements(t *testing.T) {
|
||||
om := NewOrderedMap[string, int]()
|
||||
|
||||
om.Set("a", 1)
|
||||
om.Set("b", 2)
|
||||
om.Set("c", 3)
|
||||
|
||||
assert := internal.NewAssert(t, "TestOrderedMap_Eelements")
|
||||
|
||||
elements := []struct {
|
||||
Key string
|
||||
Value int
|
||||
}{
|
||||
{"a", 1},
|
||||
{"b", 2},
|
||||
{"c", 3},
|
||||
}
|
||||
|
||||
assert.Equal(elements, om.Elements())
|
||||
}
|
||||
|
||||
func TestOrderedMap_Range(t *testing.T) {
|
||||
om := NewOrderedMap[string, int]()
|
||||
|
||||
om.Set("a", 1)
|
||||
om.Set("b", 2)
|
||||
om.Set("c", 3)
|
||||
om.Set("d", 4)
|
||||
|
||||
assert := internal.NewAssert(t, "TestOrderedMap_Range")
|
||||
|
||||
var keys []string
|
||||
om.Range(func(key string, value int) bool {
|
||||
keys = append(keys, key)
|
||||
return key != "c"
|
||||
})
|
||||
|
||||
assert.Equal([]string{"a", "b", "c"}, keys)
|
||||
}
|
||||
|
||||
func TestOrderedMap_Iter(t *testing.T) {
|
||||
om := NewOrderedMap[string, int]()
|
||||
|
||||
om.Set("a", 1)
|
||||
om.Set("b", 2)
|
||||
om.Set("c", 3)
|
||||
|
||||
assert := internal.NewAssert(t, "TestOrderedMap_Iter")
|
||||
|
||||
var items []struct {
|
||||
Key string
|
||||
Value int
|
||||
}
|
||||
|
||||
iterCh := om.Iter()
|
||||
|
||||
for item := range iterCh {
|
||||
items = append(items, item)
|
||||
}
|
||||
|
||||
expected := []struct {
|
||||
Key string
|
||||
Value int
|
||||
}{
|
||||
{"a", 1},
|
||||
{"b", 2},
|
||||
{"c", 3},
|
||||
}
|
||||
|
||||
assert.Equal(expected, items)
|
||||
}
|
||||
|
||||
func TestOrderedMap_ReverseIter(t *testing.T) {
|
||||
om := NewOrderedMap[string, int]()
|
||||
|
||||
om.Set("a", 1)
|
||||
om.Set("b", 2)
|
||||
om.Set("c", 3)
|
||||
|
||||
assert := internal.NewAssert(t, "TestOrderedMap_ReverseIter")
|
||||
|
||||
var items []struct {
|
||||
Key string
|
||||
Value int
|
||||
}
|
||||
|
||||
iterCh := om.ReverseIter()
|
||||
|
||||
for item := range iterCh {
|
||||
items = append(items, item)
|
||||
}
|
||||
|
||||
expected := []struct {
|
||||
Key string
|
||||
Value int
|
||||
}{
|
||||
{"c", 3},
|
||||
{"b", 2},
|
||||
{"a", 1},
|
||||
}
|
||||
|
||||
assert.Equal(expected, items)
|
||||
}
|
||||
|
||||
func TestOrderedMap_SortByKey(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestOrderedMap_SortByKey")
|
||||
|
||||
om := NewOrderedMap[string, int]()
|
||||
|
||||
om.Set("d", 4)
|
||||
om.Set("b", 2)
|
||||
om.Set("c", 3)
|
||||
om.Set("a", 1)
|
||||
|
||||
om.SortByKey(func(a, b string) bool {
|
||||
return a < b
|
||||
})
|
||||
|
||||
assert.Equal([]string{"a", "b", "c", "d"}, om.Keys())
|
||||
}
|
||||
|
||||
func TestOrderedMap_MarshalJSON(t *testing.T) {
|
||||
om := NewOrderedMap[string, int]()
|
||||
|
||||
om.Set("a", 1)
|
||||
om.Set("b", 2)
|
||||
om.Set("c", 3)
|
||||
|
||||
assert := internal.NewAssert(t, "TestOrderedMap_MarshalJSON")
|
||||
|
||||
jsonBytes, err := om.MarshalJSON()
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("MarshalJSON error: %v", err)
|
||||
}
|
||||
|
||||
assert.Equal(`{"a":1,"b":2,"c":3}`, string(jsonBytes))
|
||||
}
|
||||
|
||||
func TestOrderedMap_UnmarshalJSON(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestOrderedMap_UnmarshalJSON")
|
||||
|
||||
jsonStr := `{"a":1,"b":2,"c":3}`
|
||||
|
||||
om := NewOrderedMap[string, int]()
|
||||
err := om.UnmarshalJSON([]byte(jsonStr))
|
||||
if err != nil {
|
||||
t.Errorf("MarshalJSON error: %v", err)
|
||||
}
|
||||
|
||||
assert.Equal(3, om.Len())
|
||||
assert.Equal(true, om.Contains("a"))
|
||||
assert.Equal(true, om.Contains("b"))
|
||||
assert.Equal(true, om.Contains("c"))
|
||||
}
|
||||
@@ -16,12 +16,20 @@ func TestContain(t *testing.T) {
|
||||
|
||||
assert := internal.NewAssert(t, "TestContain")
|
||||
|
||||
assert.Equal(true, Contain([]string{"a", "b", "c"}, "a"))
|
||||
assert.Equal(false, Contain([]string{"a", "b", "c"}, "d"))
|
||||
assert.Equal(true, Contain([]string{""}, ""))
|
||||
assert.Equal(false, Contain([]string{}, ""))
|
||||
tests := []struct {
|
||||
slice []string
|
||||
give string
|
||||
want bool
|
||||
}{
|
||||
{[]string{"a", "b", "c"}, "a", true},
|
||||
{[]string{"a", "b", "c"}, "d", false},
|
||||
{[]string{""}, "", true},
|
||||
{[]string{}, "", false},
|
||||
}
|
||||
|
||||
assert.Equal(true, Contain([]int{1, 2, 3}, 1))
|
||||
for _, tt := range tests {
|
||||
assert.Equal(tt.want, Contain(tt.slice, tt.give))
|
||||
}
|
||||
}
|
||||
|
||||
func TestContainBy(t *testing.T) {
|
||||
@@ -30,32 +38,53 @@ func TestContainBy(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestContainBy")
|
||||
|
||||
type foo struct {
|
||||
A string
|
||||
B int
|
||||
a string
|
||||
b int
|
||||
}
|
||||
|
||||
array1 := []foo{{A: "1", B: 1}, {A: "2", B: 2}}
|
||||
result1 := ContainBy(array1, func(f foo) bool { return f.A == "1" && f.B == 1 })
|
||||
result2 := ContainBy(array1, func(f foo) bool { return f.A == "2" && f.B == 1 })
|
||||
tests := []struct {
|
||||
slice []foo
|
||||
predicateFn func(f foo) bool
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
[]foo{{a: "1", b: 1}, {a: "2", b: 2}},
|
||||
func(f foo) bool { return f.a == "1" && f.b == 1 },
|
||||
true,
|
||||
},
|
||||
{
|
||||
[]foo{{a: "1", b: 1}, {a: "2", b: 2}},
|
||||
func(f foo) bool { return f.a == "2" && f.b == 1 },
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
array2 := []string{"a", "b", "c"}
|
||||
result3 := ContainBy(array2, func(t string) bool { return t == "a" })
|
||||
result4 := ContainBy(array2, func(t string) bool { return t == "d" })
|
||||
|
||||
assert.Equal(true, result1)
|
||||
assert.Equal(false, result2)
|
||||
assert.Equal(true, result3)
|
||||
assert.Equal(false, result4)
|
||||
for _, tt := range tests {
|
||||
assert.Equal(tt.want, ContainBy(tt.slice, tt.predicateFn))
|
||||
}
|
||||
}
|
||||
|
||||
func TestContainSubSlice(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestContainSubSlice")
|
||||
assert.Equal(true, ContainSubSlice([]string{"a", "a", "b", "c"}, []string{"a", "a"}))
|
||||
assert.Equal(false, ContainSubSlice([]string{"a", "a", "b", "c"}, []string{"a", "d"}))
|
||||
assert.Equal(true, ContainSubSlice([]int{1, 2, 3}, []int{1, 2}))
|
||||
assert.Equal(false, ContainSubSlice([]int{1, 2, 3}, []int{0, 1}))
|
||||
|
||||
tests := []struct {
|
||||
slice []string
|
||||
subSlice []string
|
||||
want bool
|
||||
}{
|
||||
{[]string{"a", "b", "c"}, []string{"a", "b"}, true},
|
||||
{[]string{"a", "b", "c"}, []string{"a", "d"}, false},
|
||||
{[]string{"a", "b", "c"}, []string{"a", "b", "c"}, true},
|
||||
{[]string{"a", "b", "c"}, []string{"a", "b", "c", "d"}, false},
|
||||
{[]string{"a", "b", ""}, []string{"a", ""}, true},
|
||||
{[]string{""}, []string{""}, true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
assert.Equal(tt.want, ContainSubSlice(tt.slice, tt.subSlice))
|
||||
}
|
||||
}
|
||||
|
||||
func TestChunk(t *testing.T) {
|
||||
@@ -63,29 +92,24 @@ func TestChunk(t *testing.T) {
|
||||
|
||||
assert := internal.NewAssert(t, "TestChunk")
|
||||
|
||||
arr := []string{"a", "b", "c", "d", "e"}
|
||||
tests := []struct {
|
||||
slice []string
|
||||
chuanSize int
|
||||
want [][]string
|
||||
}{
|
||||
{[]string{"a", "b", "c", "d", "e"}, -1, [][]string{}},
|
||||
{[]string{"a", "b", "c", "d", "e"}, 0, [][]string{}},
|
||||
{[]string{"a", "b", "c", "d", "e"}, 1, [][]string{{"a"}, {"b"}, {"c"}, {"d"}, {"e"}}},
|
||||
{[]string{"a", "b", "c", "d", "e"}, 2, [][]string{{"a", "b"}, {"c", "d"}, {"e"}}},
|
||||
{[]string{"a", "b", "c", "d", "e"}, 3, [][]string{{"a", "b", "c"}, {"d", "e"}}},
|
||||
{[]string{"a", "b", "c", "d", "e"}, 4, [][]string{{"a", "b", "c", "d"}, {"e"}}},
|
||||
{[]string{"a", "b", "c", "d", "e"}, 5, [][]string{{"a", "b", "c", "d", "e"}}},
|
||||
{[]string{"a", "b", "c", "d", "e"}, 6, [][]string{{"a", "b", "c", "d", "e"}}},
|
||||
}
|
||||
|
||||
assert.Equal([][]string{}, Chunk(arr, -1))
|
||||
|
||||
assert.Equal([][]string{}, Chunk(arr, 0))
|
||||
|
||||
r1 := [][]string{{"a"}, {"b"}, {"c"}, {"d"}, {"e"}}
|
||||
assert.Equal(r1, Chunk(arr, 1))
|
||||
|
||||
r2 := [][]string{{"a", "b"}, {"c", "d"}, {"e"}}
|
||||
assert.Equal(r2, Chunk(arr, 2))
|
||||
|
||||
r3 := [][]string{{"a", "b", "c"}, {"d", "e"}}
|
||||
assert.Equal(r3, Chunk(arr, 3))
|
||||
|
||||
r4 := [][]string{{"a", "b", "c", "d"}, {"e"}}
|
||||
assert.Equal(r4, Chunk(arr, 4))
|
||||
|
||||
r5 := [][]string{{"a", "b", "c", "d", "e"}}
|
||||
assert.Equal(r5, Chunk(arr, 5))
|
||||
|
||||
r6 := [][]string{{"a", "b", "c", "d", "e"}}
|
||||
assert.Equal(r6, Chunk(arr, 6))
|
||||
for _, tt := range tests {
|
||||
assert.Equal(tt.want, Chunk(tt.slice, tt.chuanSize))
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompact(t *testing.T) {
|
||||
@@ -134,6 +158,7 @@ func TestEqual(t *testing.T) {
|
||||
|
||||
assert.Equal(true, Equal(slice1, slice2))
|
||||
assert.Equal(false, Equal(slice1, slice3))
|
||||
assert.Equal(false, Equal(slice2, slice3))
|
||||
}
|
||||
|
||||
// go test -fuzz=Fuzz -fuzztime=10s .
|
||||
@@ -163,12 +188,27 @@ func TestEvery(t *testing.T) {
|
||||
|
||||
assert := internal.NewAssert(t, "TestEvery")
|
||||
|
||||
nums := []int{1, 2, 3, 5}
|
||||
isEven := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
isOdd := func(i, num int) bool {
|
||||
return num%2 == 1
|
||||
}
|
||||
|
||||
assert.Equal(false, Every(nums, isEven))
|
||||
tests := []struct {
|
||||
slice []int
|
||||
predicateFn func(i, num int) bool
|
||||
want bool
|
||||
}{
|
||||
{[]int{1, 3, 5, 7}, isOdd, true},
|
||||
{[]int{2, 4, 6, 8}, isEven, true},
|
||||
{[]int{1, 2, 3, 4}, isOdd, false},
|
||||
{[]int{1, 2, 3, 4}, isEven, false},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
assert.Equal(tt.want, Every(tt.slice, tt.predicateFn))
|
||||
}
|
||||
}
|
||||
|
||||
func TestNone(t *testing.T) {
|
||||
@@ -176,12 +216,27 @@ func TestNone(t *testing.T) {
|
||||
|
||||
assert := internal.NewAssert(t, "TestNone")
|
||||
|
||||
nums := []int{1, 2, 3, 5}
|
||||
check := func(i, num int) bool {
|
||||
isEven := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
isOdd := func(i, num int) bool {
|
||||
return num%2 == 1
|
||||
}
|
||||
|
||||
assert.Equal(false, None(nums, check))
|
||||
tests := []struct {
|
||||
slice []int
|
||||
predicateFn func(i, num int) bool
|
||||
want bool
|
||||
}{
|
||||
{[]int{1, 3, 5, 7}, isEven, true},
|
||||
{[]int{2, 4, 6, 8}, isOdd, true},
|
||||
{[]int{1, 2, 3, 4}, isOdd, false},
|
||||
{[]int{1, 2, 3, 4}, isEven, false},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
assert.Equal(tt.want, None(tt.slice, tt.predicateFn))
|
||||
}
|
||||
}
|
||||
|
||||
func TestSome(t *testing.T) {
|
||||
@@ -189,12 +244,27 @@ func TestSome(t *testing.T) {
|
||||
|
||||
assert := internal.NewAssert(t, "TestSome")
|
||||
|
||||
nums := []int{1, 2, 3, 5}
|
||||
hasEven := func(i, num int) bool {
|
||||
isEven := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
isOdd := func(i, num int) bool {
|
||||
return num%2 == 1
|
||||
}
|
||||
|
||||
assert.Equal(true, Some(nums, hasEven))
|
||||
tests := []struct {
|
||||
slice []int
|
||||
predicateFn func(i, num int) bool
|
||||
want bool
|
||||
}{
|
||||
{[]int{1, 3, 5, 7}, isEven, false},
|
||||
{[]int{2, 4, 6, 8}, isOdd, false},
|
||||
{[]int{1, 2, 3, 4}, isOdd, true},
|
||||
{[]int{1, 2, 3, 4}, isEven, true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
assert.Equal(tt.want, Some(tt.slice, tt.predicateFn))
|
||||
}
|
||||
}
|
||||
|
||||
func TestFilter(t *testing.T) {
|
||||
@@ -202,33 +272,37 @@ func TestFilter(t *testing.T) {
|
||||
|
||||
assert := internal.NewAssert(t, "TestFilter")
|
||||
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
isEven := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
t.Run("filter int slice", func(t *testing.T) {
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
isEven := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
|
||||
assert.Equal([]int{2, 4}, Filter(nums, isEven))
|
||||
assert.Equal([]int{2, 4}, Filter(nums, isEven))
|
||||
})
|
||||
|
||||
type student struct {
|
||||
name string
|
||||
age int
|
||||
}
|
||||
students := []student{
|
||||
{"a", 10},
|
||||
{"b", 11},
|
||||
{"c", 12},
|
||||
{"d", 13},
|
||||
{"e", 14},
|
||||
}
|
||||
studentsOfAageGreat12 := []student{
|
||||
{"d", 13},
|
||||
{"e", 14},
|
||||
}
|
||||
filterFunc := func(i int, s student) bool {
|
||||
return s.age > 12
|
||||
}
|
||||
t.Run("filter struct slice", func(t *testing.T) {
|
||||
type student struct {
|
||||
name string
|
||||
age int
|
||||
}
|
||||
students := []student{
|
||||
{"a", 10},
|
||||
{"b", 11},
|
||||
{"c", 12},
|
||||
{"d", 13},
|
||||
{"e", 14},
|
||||
}
|
||||
studentsOfAgeGreat12 := []student{
|
||||
{"d", 13},
|
||||
{"e", 14},
|
||||
}
|
||||
filterFunc := func(i int, s student) bool {
|
||||
return s.age > 12
|
||||
}
|
||||
|
||||
assert.Equal(studentsOfAageGreat12, Filter(students, filterFunc))
|
||||
assert.Equal(studentsOfAgeGreat12, Filter(students, filterFunc))
|
||||
})
|
||||
}
|
||||
|
||||
func TestGroupBy(t *testing.T) {
|
||||
@@ -249,6 +323,8 @@ func TestGroupBy(t *testing.T) {
|
||||
func TestGroupWith(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestGroupWith")
|
||||
|
||||
nums := []float64{6.1, 4.2, 6.3}
|
||||
floor := func(num float64) float64 {
|
||||
return math.Floor(num)
|
||||
@@ -257,9 +333,8 @@ func TestGroupWith(t *testing.T) {
|
||||
4: {4.2},
|
||||
6: {6.1, 6.3},
|
||||
}
|
||||
actual := GroupWith(nums, floor)
|
||||
assert := internal.NewAssert(t, "TestGroupWith")
|
||||
assert.Equal(expected, actual)
|
||||
|
||||
assert.Equal(expected, GroupWith(nums, floor))
|
||||
}
|
||||
|
||||
func TestCount(t *testing.T) {
|
||||
@@ -295,8 +370,15 @@ func TestFind(t *testing.T) {
|
||||
result, ok := Find(nums, even)
|
||||
|
||||
assert := internal.NewAssert(t, "TestFind")
|
||||
|
||||
assert.Equal(true, ok)
|
||||
assert.Equal(2, *result)
|
||||
|
||||
_, ok = Find(nums, func(_ int, v int) bool {
|
||||
return v == 6
|
||||
})
|
||||
|
||||
assert.Equal(false, ok)
|
||||
}
|
||||
|
||||
func TestFindBy(t *testing.T) {
|
||||
@@ -358,19 +440,6 @@ func TestFindLast(t *testing.T) {
|
||||
assert.Equal(4, *result)
|
||||
}
|
||||
|
||||
func TestFindFoundNothing(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
nums := []int{1, 1, 1, 1, 1, 1}
|
||||
findFunc := func(i, num int) bool {
|
||||
return num > 1
|
||||
}
|
||||
_, ok := Find(nums, findFunc)
|
||||
|
||||
assert := internal.NewAssert(t, "TestFindFoundNothing")
|
||||
assert.Equal(false, ok)
|
||||
}
|
||||
|
||||
func TestFlatten(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -633,14 +702,12 @@ func TestReduceBy(t *testing.T) {
|
||||
result1 := ReduceBy([]int{1, 2, 3, 4}, 0, func(_ int, item int, agg int) int {
|
||||
return agg + item
|
||||
})
|
||||
assert.Equal(10, result1)
|
||||
|
||||
result2 := ReduceBy([]int{1, 2, 3, 4}, "", func(_ int, item int, agg string) string {
|
||||
return agg + fmt.Sprintf("%v", item)
|
||||
})
|
||||
|
||||
assert.Equal(10, result1)
|
||||
assert.Equal("1234", result2)
|
||||
|
||||
}
|
||||
|
||||
func TestReduceRight(t *testing.T) {
|
||||
@@ -692,15 +759,23 @@ func TestDeleteAt(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestDeleteAt")
|
||||
arr := []int{1, 2, 3, 4, 5}
|
||||
|
||||
assert.Equal([]int{2, 3, 4, 5}, DeleteAt(arr, 0))
|
||||
assert.Equal([]int{1, 2, 3, 4}, DeleteAt(arr, 4))
|
||||
tests := []struct {
|
||||
slice []int
|
||||
deletePos int
|
||||
wang []int
|
||||
}{
|
||||
{[]int{1, 2, 3, 4, 5}, 0, []int{2, 3, 4, 5}},
|
||||
{[]int{1, 2, 3, 4, 5}, 1, []int{1, 3, 4, 5}},
|
||||
{[]int{1, 2, 3, 4, 5}, 2, []int{1, 2, 4, 5}},
|
||||
{[]int{1, 2, 3, 4, 5}, 3, []int{1, 2, 3, 5}},
|
||||
{[]int{1, 2, 3, 4, 5}, 4, []int{1, 2, 3, 4}},
|
||||
{[]int{1, 2, 3, 4, 5}, 5, []int{1, 2, 3, 4}},
|
||||
}
|
||||
|
||||
assert.Equal([]int{1, 2, 3, 4}, DeleteAt(arr, 5))
|
||||
assert.Equal([]int{1, 2, 3, 4}, DeleteAt(arr, 6))
|
||||
|
||||
assert.Equal([]int{1, 2, 3, 4, 5}, arr)
|
||||
for _, tt := range tests {
|
||||
assert.Equal(tt.wang, DeleteAt(tt.slice, tt.deletePos))
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteRange(t *testing.T) {
|
||||
@@ -720,16 +795,24 @@ func TestDrop(t *testing.T) {
|
||||
|
||||
assert := internal.NewAssert(t, "TestDrop")
|
||||
|
||||
assert.Equal([]int{}, Drop([]int{}, 0))
|
||||
assert.Equal([]int{}, Drop([]int{}, 1))
|
||||
assert.Equal([]int{}, Drop([]int{}, -1))
|
||||
tests := []struct {
|
||||
slice []int
|
||||
dropNum int
|
||||
want []int
|
||||
}{
|
||||
{[]int{}, 0, []int{}},
|
||||
{[]int{}, 1, []int{}},
|
||||
{[]int{}, -1, []int{}},
|
||||
{[]int{1, 2, 3, 4, 5}, -1, []int{1, 2, 3, 4, 5}},
|
||||
{[]int{1, 2, 3, 4, 5}, 0, []int{1, 2, 3, 4, 5}},
|
||||
{[]int{1, 2, 3, 4, 5}, 1, []int{2, 3, 4, 5}},
|
||||
{[]int{1, 2, 3, 4, 5}, 5, []int{}},
|
||||
{[]int{1, 2, 3, 4, 5}, 6, []int{}},
|
||||
}
|
||||
|
||||
assert.Equal([]int{1, 2, 3, 4, 5}, Drop([]int{1, 2, 3, 4, 5}, 0))
|
||||
assert.Equal([]int{2, 3, 4, 5}, Drop([]int{1, 2, 3, 4, 5}, 1))
|
||||
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{1, 2, 3, 4, 5}, Drop([]int{1, 2, 3, 4, 5}, -1))
|
||||
for _, tt := range tests {
|
||||
assert.Equal(tt.want, Drop(tt.slice, tt.dropNum))
|
||||
}
|
||||
}
|
||||
|
||||
func TestDropRight(t *testing.T) {
|
||||
@@ -737,16 +820,23 @@ 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))
|
||||
tests := []struct {
|
||||
slice []int
|
||||
dropNum int
|
||||
want []int
|
||||
}{
|
||||
{[]int{}, 0, []int{}},
|
||||
{[]int{}, 1, []int{}},
|
||||
{[]int{}, -1, []int{}},
|
||||
{[]int{1, 2, 3, 4, 5}, -1, []int{1, 2, 3, 4, 5}},
|
||||
{[]int{1, 2, 3, 4, 5}, 0, []int{1, 2, 3, 4, 5}},
|
||||
{[]int{1, 2, 3, 4, 5}, 1, []int{1, 2, 3, 4}},
|
||||
{[]int{}, 5, []int{}},
|
||||
{[]int{}, 6, []int{}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
assert.Equal(tt.want, DropRight(tt.slice, tt.dropNum))
|
||||
}
|
||||
}
|
||||
|
||||
func TestDropWhile(t *testing.T) {
|
||||
@@ -754,22 +844,19 @@ func TestDropWhile(t *testing.T) {
|
||||
|
||||
assert := internal.NewAssert(t, "TestDropWhile")
|
||||
|
||||
numbers := []int{1, 2, 3, 4, 5}
|
||||
tests := []struct {
|
||||
slice []int
|
||||
fn func(int) bool
|
||||
want []int
|
||||
}{
|
||||
{[]int{1, 2, 3, 4, 5}, func(n int) bool { return n != 2 }, []int{2, 3, 4, 5}},
|
||||
{[]int{1, 2, 3, 4, 5}, func(n int) bool { return true }, []int{}},
|
||||
{[]int{1, 2, 3, 4, 5}, func(n int) bool { return n == 0 }, []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)
|
||||
for _, tt := range tests {
|
||||
assert.Equal(tt.want, DropWhile(tt.slice, tt.fn))
|
||||
}
|
||||
}
|
||||
|
||||
func TestDropRightWhile(t *testing.T) {
|
||||
@@ -777,22 +864,19 @@ func TestDropRightWhile(t *testing.T) {
|
||||
|
||||
assert := internal.NewAssert(t, "TestDropRightWhile")
|
||||
|
||||
numbers := []int{1, 2, 3, 4, 5}
|
||||
tests := []struct {
|
||||
slice []int
|
||||
fn func(int) bool
|
||||
want []int
|
||||
}{
|
||||
{[]int{1, 2, 3, 4, 5}, func(n int) bool { return n != 2 }, []int{1, 2}},
|
||||
{[]int{1, 2, 3, 4, 5}, func(n int) bool { return true }, []int{}},
|
||||
{[]int{1, 2, 3, 4, 5}, func(n int) bool { return n == 0 }, []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)
|
||||
for _, tt := range tests {
|
||||
assert.Equal(tt.want, DropRightWhile(tt.slice, tt.fn))
|
||||
}
|
||||
}
|
||||
|
||||
func TestInsertAt(t *testing.T) {
|
||||
@@ -800,15 +884,25 @@ func TestInsertAt(t *testing.T) {
|
||||
|
||||
assert := internal.NewAssert(t, "TestInsertAt")
|
||||
|
||||
strs := []string{"a", "b", "c"}
|
||||
assert.Equal([]string{"a", "b", "c"}, InsertAt(strs, -1, "1"))
|
||||
assert.Equal([]string{"a", "b", "c"}, InsertAt(strs, 4, "1"))
|
||||
assert.Equal([]string{"1", "a", "b", "c"}, InsertAt(strs, 0, "1"))
|
||||
assert.Equal([]string{"a", "1", "b", "c"}, InsertAt(strs, 1, "1"))
|
||||
assert.Equal([]string{"a", "b", "1", "c"}, InsertAt(strs, 2, "1"))
|
||||
assert.Equal([]string{"a", "b", "c", "1"}, InsertAt(strs, 3, "1"))
|
||||
assert.Equal([]string{"1", "2", "3", "a", "b", "c"}, InsertAt(strs, 0, []string{"1", "2", "3"}))
|
||||
assert.Equal([]string{"a", "b", "c", "1", "2", "3"}, InsertAt(strs, 3, []string{"1", "2", "3"}))
|
||||
tests := []struct {
|
||||
slice []string
|
||||
insertPos int
|
||||
insertValue any
|
||||
want []string
|
||||
}{
|
||||
{[]string{"a", "b", "c"}, -1, "1", []string{"a", "b", "c"}},
|
||||
{[]string{"a", "b", "c"}, 4, "1", []string{"a", "b", "c"}},
|
||||
{[]string{"a", "b", "c"}, 0, "1", []string{"1", "a", "b", "c"}},
|
||||
{[]string{"a", "b", "c"}, 1, "1", []string{"a", "1", "b", "c"}},
|
||||
{[]string{"a", "b", "c"}, 2, "1", []string{"a", "b", "1", "c"}},
|
||||
{[]string{"a", "b", "c"}, 3, "1", []string{"a", "b", "c", "1"}},
|
||||
{[]string{"a", "b", "c"}, 0, []string{"1", "2", "3"}, []string{"1", "2", "3", "a", "b", "c"}},
|
||||
{[]string{"a", "b", "c"}, 3, []string{"1", "2", "3"}, []string{"a", "b", "c", "1", "2", "3"}},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
assert.Equal(tt.want, InsertAt(tt.slice, tt.insertPos, tt.insertValue))
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateAt(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user