1
0
mirror of https://github.com/duke-git/lancet.git synced 2026-02-05 13:22:26 +08:00

Merge branch 'rc'

This commit is contained in:
dudaodong
2024-09-02 14:31:59 +08:00
14 changed files with 2827 additions and 267 deletions

View File

@@ -1200,9 +1200,6 @@ import "github.com/duke-git/lancet/v2/retry"
- **<big>RetryFunc</big>** : 重试执行的函数。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/retry.md#RetryFunc)]
[[play](https://go.dev/play/p/nk2XRmagfVF)]
- **<big>RetryDuration</big>** : 设置重试间隔时间,默认 3 秒。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/retry.md#RetryDuration)]
[[play](https://go.dev/play/p/nk2XRmagfVF)]
- **<big>RetryTimes</big>** : 设置重试次数,默认 5。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/retry.md#RetryTimes)]
[[play](https://go.dev/play/p/ssfVeU2SwLO)]

View File

@@ -47,6 +47,24 @@ import (
- [MapToStruct](#MapToStruct)
- [ToSortedSlicesDefault](#ToSortedSlicesDefault)
- [ToSortedSlicesWithComparator](#ToSortedSlicesWithComparator)
- [NewOrderedMap](#NewOrderedMap)
- [OrderedMap_Set](#OrderedMap_Set)
- [OrderedMap_Get](#OrderedMap_Get)
- [OrderedMap_Front](#OrderedMap_Front)
- [OrderedMap_Back](#OrderedMap_Back)
- [OrderedMap_Delete](#OrderedMap_Delete)
- [OrderedMap_Clear](#OrderedMap_Clear)
- [OrderedMap_Len](#OrderedMap_Len)
- [OrderedMap_Keys](#OrderedMap_Keys)
- [OrderedMap_Values](#OrderedMap_Values)
- [OrderedMap_Contains](#OrderedMap_Contains)
- [OrderedMap_Range](#OrderedMap_Range)
- [OrderedMap_Elements](#OrderedMap_Elements)
- [OrderedMap_Iter](#OrderedMap_Iter)
- [OrderedMap_ReverseIter](#OrderedMap_ReverseIter)
- [OrderedMap_SortByKey](#OrderedMap_SortByKey)
- [OrderedMap_MarshalJSON](#OrderedMap_MarshalJSON)
- [OrderedMap_UnmarshalJSON](#OrderedMap_UnmarshalJSON)
- [NewConcurrentMap](#NewConcurrentMap)
- [ConcurrentMap_Get](#ConcurrentMap_Get)
- [ConcurrentMap_Set](#ConcurrentMap_Set)
@@ -56,6 +74,7 @@ import (
- [ConcurrentMap_Has](#ConcurrentMap_Has)
- [ConcurrentMap_Range](#ConcurrentMap_Range)
- [GetOrSet](#GetOrSet)
- [SortByKey](#SortByKey)
<div STYLE="page-break-after: always;"></div>
@@ -1120,6 +1139,689 @@ func main() {
}
```
### <span id="NewOrderedMap">NewOrderedMap</span>
<p>创建有序映射。有序映射是键值对的集合,其中键是唯一的,并且保留键插入的顺序。</p>
<b>函数签名:</b>
```go
func NewOrderedMap[K comparable, V any]() *OrderedMap[K, V]
```
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
om := maputil.NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
val1, ok := om.Get("a")
fmt.Println(val1, ok)
val2, ok := om.Get("d")
fmt.Println(val2, ok)
// Output:
// 1 true
// 0 false
}
```
### <span id="OrderedMap_Set">OrderedMap_Set</span>
<p>设置给定的键值对。</p>
<b>函数签名:</b>
```go
func (om *OrderedMap[K, V]) Set(key K, value V)
```
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
om := maputil.NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
val1, ok := om.Get("a")
fmt.Println(val1, ok)
val2, ok := om.Get("d")
fmt.Println(val2, ok)
// Output:
// 1 true
// 0 false
}
```
### <span id="OrderedMap_Get">OrderedMap_Get</span>
<p>返回给定键的值。</p>
<b>函数签名:</b>
```go
func (om *OrderedMap[K, V]) Get(key K) (V, bool)
```
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
om := maputil.NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
val1, ok := om.Get("a")
fmt.Println(val1, ok)
val2, ok := om.Get("d")
fmt.Println(val2, ok)
// Output:
// 1 true
// 0 false
}
```
### <span id="OrderedMap_Delete">OrderedMap_Delete</span>
<p>删除给定键的键值对。</p>
<b>函数签名:</b>
```go
func (om *OrderedMap[K, V]) Delete(key K)
```
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
om := maputil.NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
om.Delete("b")
fmt.Println(om.Keys())
// Output:
// [a c]
}
```
### <span id="OrderedMap_Clear">OrderedMap_Clear</span>
<p>清空map数据。</p>
<b>函数签名:</b>
```go
func (om *OrderedMap[K, V]) Clear()
```
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
om := maputil.NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
om.Clear()
fmt.Println(om.Keys())
// Output:
// []
}
```
### <span id="OrderedMap_Front">OrderedMap_Front</span>
<p>返回第一个键值对。</p>
<b>函数签名:</b>
```go
func (om *OrderedMap[K, V]) Front() (struct {
Key K
Value V
}, bool)
```
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
om := maputil.NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
frontElement, ok := om.Front()
fmt.Println(frontElement)
fmt.Println(ok)
// Output:
// {a 1}
// true
}
```
### <span id="OrderedMap_Back">OrderedMap_Back</span>
<p>返回最后一个键值对。</p>
<b>函数签名:</b>
```go
func (om *OrderedMap[K, V]) Back() (struct {
Key K
Value V
}, bool)
```
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
om := maputil.NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
frontElement, ok := om.Front()
fmt.Println(frontElement)
fmt.Println(ok)
// Output:
// {a 1}
// true
}
```
### <span id="OrderedMap_Range">OrderedMap_Range</span>
<p>为每个键值对调用给定的函数。</p>
<b>函数签名:</b>
```go
func (om *OrderedMap[K, V]) Range(iteratee func(key K, value V) bool)
```
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
om := maputil.NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
om.Range(func(key string, value int) bool {
fmt.Println(key, value)
return true
})
// Output:
// a 1
// b 2
// c 3
}
```
### <span id="OrderedMap_Keys">OrderedMap_Keys</span>
<p>按顺序返回键的切片。</p>
<b>函数签名:</b>
```go
func (om *OrderedMap[K, V]) Keys() []K
```
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
om := maputil.NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
keys := om.Keys()
fmt.Println(keys)
// Output:
// [a b c]
}
```
### <span id="OrderedMap_Values">OrderedMap_Values</span>
<p>按顺序返回值的切片。</p>
<b>函数签名:</b>
```go
func (om *OrderedMap[K, V]) Values() []V
```
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
om := maputil.NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
values := om.Values()
fmt.Println(values)
// Output:
// [1 2 3]
}
```
### <span id="OrderedMap_Elements">OrderedMap_Elements</span>
<p>按顺序返回键值对。</p>
<b>函数签名:</b>
```go
func (om *OrderedMap[K, V]) Elements() []struct
```
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
om := maputil.NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
elements := om.Elements()
fmt.Println(elements)
// Output:
// [{a 1} {b 2} {c 3}]
}
```
### <span id="OrderedMap_Len">OrderedMap_Len</span>
<p>返回键值对的数量。</p>
<b>函数签名:</b>
```go
func (om *OrderedMap[K, V]) Len() int
```
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
om := maputil.NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
om.Len()
fmt.Println(om.Len())
// Output:
// 3
}
```
### <span id="OrderedMap_Contains">OrderedMap_Contains</span>
<p>如果给定的键存在则返回true。</p>
<b>函数签名:</b>
```go
func (om *OrderedMap[K, V]) Contains(key K) bool
```
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
om := maputil.NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
result1 := om.Contains("a")
result2 := om.Contains("d")
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}
```
### <span id="OrderedMap_Iter">OrderedMap_Iter</span>
<p>返回按顺序产生键值对的通道。</p>
<b>函数签名:</b>
```go
func (om *OrderedMap[K, V]) Iter() <-chan struct {
Key K
Value V
}
```
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
om := maputil.NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
for elem := range om.Iter() {
fmt.Println(elem)
}
// Output:
// {a 1}
// {b 2}
// {c 3}
}
```
### <span id="OrderedMap_ReverseIter">OrderedMap_ReverseIter</span>
<p>返回以相反顺序产生键值对的通道。</p>
<b>函数签名:</b>
```go
func (om *OrderedMap[K, V]) ReverseIter() <-chan struct {
Key K
Value V
}
```
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
om := maputil.NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
for elem := range om.ReverseIter() {
fmt.Println(elem)
}
// Output:
// {c 3}
// {b 2}
// {a 1}
}
```
### <span id="OrderedMap_SortByKey">OrderedMap_SortByKey</span>
<p>使用传入的比较函数排序map key。</p>
<b>函数签名:</b>
```go
func (om *OrderedMap[K, V]) SortByKey(less func(a, b K) bool)
```
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
om := maputil.NewOrderedMap[string, int]()
om.Set(3, "c")
om.Set(1, "a")
om.Set(4, "d")
om.Set(2, "b")
om.SortByKey(func(a, b int) bool {
return a < b
})
fmt.Println(om.Elements())
// Output:
// [{1 a} {2 b} {3 c} {4 d}]
}
```
### <span id="OrderedMap_MarshalJSON">OrderedMap_MarshalJSON</span>
<p>实现json.Marshaler接口。</p>
<b>函数签名:</b>
```go
func (om *OrderedMap[K, V]) MarshalJSON() ([]byte, error)
```
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
om := maputil.NewOrderedMap[string, int]()
om.Set(3, "c")
om.Set(1, "a")
om.Set(4, "d")
om.Set(2, "b")
b, _ := om.MarshalJSON()
fmt.Println(string(b))
// Output:
// {"a":1,"b":2,"c":3}
}
```
### <span id="OrderedMap_UnmarshalJSON">OrderedMap_UnmarshalJSON</span>
<p>实现json.Unmarshaler接口。</p>
<b>函数签名:</b>
```go
func (om *OrderedMap[K, V]) UnmarshalJSON(data []byte) error
```
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
om := maputil.NewOrderedMap[string, int]()
data := []byte(`{"a":1,"b":2,"c":3}`)
om.UnmarshalJSON(data)
fmt.Println(om.Elements())
// Output:
}
```
### <span id="NewConcurrentMap">NewConcurrentMap</span>
<p>ConcurrentMap协程安全的map结构。</p>
@@ -1522,4 +2224,41 @@ func main() {
// a
// b
}
```
### <span id="SortByKey">SortByKey</span>
<p>对传入的map根据key进行排序返回排序后的map。</p>
<b>函数签名:</b>
```go
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>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m := map[int]string{
3: "c",
1: "a",
4: "d",
2: "b",
}
result := maputil.SortByKey(m)
fmt.Println(result)
// Output:
// map[1:a 2:b 3:c 4:d]
}
```

View File

@@ -70,7 +70,7 @@ func main() {
return errors.New("error occurs")
}
duration := retry.RetryDuration(time.Microsecond*50)
duration := retry.RetryWithLinearBackoff(time.Microsecond*50)
retry.Retry(increaseNumber,
duration,
@@ -116,7 +116,7 @@ func main() {
return errors.New("error occurs")
}
duration := retry.RetryDuration(time.Microsecond*50)
duration := retry.RetryWithLinearBackoff(time.Microsecond*50)
err := retry.Retry(increaseNumber, duration)
if err != nil {
@@ -173,52 +173,6 @@ func main() {
}
```
### <span id="RetryDuration">RetryDuration</span>
<p>设置重试间隔时间默认3秒</p>
<b>函数签名:</b>
```go
func RetryDuration(d time.Duration)
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/nk2XRmagfVF)</span></b>
```go
package main
import (
"fmt"
"errors"
"log"
"github.com/duke-git/lancet/v2/retry"
)
func main() {
number := 0
increaseNumber := func() error {
number++
if number == 3 {
return nil
}
return errors.New("error occurs")
}
duration := retry.RetryDuration(time.Microsecond*50)
err := retry.Retry(increaseNumber, duration)
if err != nil {
return
}
fmt.Println(number)
// Output:
// 3
}
```
### <span id="Retry">Retry</span>
<p>重试执行函数retryFunc直到函数运行成功或被context停止</p>
@@ -251,7 +205,7 @@ func main() {
return errors.New("error occurs")
}
duration := retry.RetryDuration(time.Microsecond*50)
duration := retry.RetryWithLinearBackoff(time.Microsecond*50)
err := retry.Retry(increaseNumber, duration)
if err != nil {

View File

@@ -241,7 +241,8 @@ func main() {
### <span id="ExecCommand">ExecCommand</span>
<p>执行shell命令返回命令的stdout和stderr字符串如果出现错误则返回错误。参数`command`是一个完整的命令字符串如ls-alinuxdirwindowsping 127.0.0.1。在linux中使用/bin/bash-c执行命令在windows中使用powershell.exe执行命令。</p>
<p>执行shell命令返回命令的stdout和stderr字符串如果出现错误则返回错误。参数`command`是一个完整的命令字符串如ls-alinuxdirwindowsping 127.0.0.1。在linux中使用/bin/bash-c执行命令在windows中使用powershell.exe执行命令。
函数的第二个参数是cmd选项控制参数类型是func(*exec.Cmd)可以通过这个参数设置cmd属性。</p>
<b>函数签名:</b>
@@ -262,7 +263,9 @@ import (
func main() {
// linux or mac
stdout, stderr, err := system.ExecCommand("ls")
stdout, stderr, err := system.ExecCommand("ls", func(cmd *exec.Cmd) {
cmd.Dir = "/tmp"
})
fmt.Println("std out: ", stdout)
fmt.Println("std err: ", stderr)
assert.Equal("", stderr)

View File

@@ -47,6 +47,24 @@ import (
- [MapToStruct](#MapToStruct)
- [ToSortedSlicesDefault](#ToSortedSlicesDefault)
- [ToSortedSlicesWithComparator](#ToSortedSlicesWithComparator)
- [NewOrderedMap](#NewOrderedMap)
- [OrderedMap_Set](#OrderedMap_Set)
- [OrderedMap_Get](#OrderedMap_Get)
- [OrderedMap_Front](#OrderedMap_Front)
- [OrderedMap_Back](#OrderedMap_Back)
- [OrderedMap_Delete](#OrderedMap_Delete)
- [OrderedMap_Clear](#OrderedMap_Clear)
- [OrderedMap_Len](#OrderedMap_Len)
- [OrderedMap_Keys](#OrderedMap_Keys)
- [OrderedMap_Values](#OrderedMap_Values)
- [OrderedMap_Contains](#OrderedMap_Contains)
- [OrderedMap_Range](#OrderedMap_Range)
- [OrderedMap_Elements](#OrderedMap_Elements)
- [OrderedMap_Iter](#OrderedMap_Iter)
- [OrderedMap_ReverseIter](#OrderedMap_ReverseIter)
- [OrderedMap_SortByKey](#OrderedMap_SortByKey)
- [OrderedMap_MarshalJSON](#OrderedMap_MarshalJSON)
- [OrderedMap_UnmarshalJSON](#OrderedMap_UnmarshalJSON)
- [NewConcurrentMap](#NewConcurrentMap)
- [ConcurrentMap_Get](#ConcurrentMap_Get)
- [ConcurrentMap_Set](#ConcurrentMap_Set)
@@ -1127,10 +1145,693 @@ func main() {
fmt.Println(values1)
// Output:
// [3 2 1]
// [c b a]
// [2024-03-30 00:00:00 +0000 UTC 2024-03-31 00:00:00 +0000 UTC 2024-04-01 00:00:00 +0000 UTC]
// [yesterday today tomorrow]
// [3 2 1]
// [c b a]
// [2024-03-30 00:00:00 +0000 UTC 2024-03-31 00:00:00 +0000 UTC 2024-04-01 00:00:00 +0000 UTC]
// [yesterday today tomorrow]
}
```
### <span id="NewOrderedMap">NewOrderedMap</span>
<p>Creates a new OrderedMap.</p>
<b>Signature:</b>
```go
func NewOrderedMap[K comparable, V any]() *OrderedMap[K, V]
```
<b>Example:<span style="float:right;display:inline-block;">[Run]()</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
om := maputil.NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
val1, ok := om.Get("a")
fmt.Println(val1, ok)
val2, ok := om.Get("d")
fmt.Println(val2, ok)
// Output:
// 1 true
// 0 false
}
```
### <span id="OrderedMap_Set">OrderedMap_Set</span>
<p>Sets the given key-value pair.</p>
<b>Signature:</b>
```go
func (om *OrderedMap[K, V]) Set(key K, value V)
```
<b>Example:<span style="float:right;display:inline-block;">[Run]()</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
om := maputil.NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
val1, ok := om.Get("a")
fmt.Println(val1, ok)
val2, ok := om.Get("d")
fmt.Println(val2, ok)
// Output:
// 1 true
// 0 false
}
```
### <span id="OrderedMap_Get">OrderedMap_Get</span>
<p>Returns the value for the given key.</p>
<b>Signature:</b>
```go
func (om *OrderedMap[K, V]) Get(key K) (V, bool)
```
<b>Example:<span style="float:right;display:inline-block;">[Run]()</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
om := maputil.NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
val1, ok := om.Get("a")
fmt.Println(val1, ok)
val2, ok := om.Get("d")
fmt.Println(val2, ok)
// Output:
// 1 true
// 0 false
}
```
### <span id="OrderedMap_Delete">OrderedMap_Delete</span>
<p>Deletes the key-value pair for the given key.</p>
<b>Signature:</b>
```go
func (om *OrderedMap[K, V]) Delete(key K)
```
<b>Example:<span style="float:right;display:inline-block;">[Run]()</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
om := maputil.NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
om.Delete("b")
fmt.Println(om.Keys())
// Output:
// [a c]
}
```
### <span id="OrderedMap_Clear">OrderedMap_Clear</span>
<p>Clears the map.</p>
<b>Signature:</b>
```go
func (om *OrderedMap[K, V]) Clear()
```
<b>Example:<span style="float:right;display:inline-block;">[Run]()</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
om := maputil.NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
om.Clear()
fmt.Println(om.Keys())
// Output:
// []
}
```
### <span id="OrderedMap_Front">OrderedMap_Front</span>
<p>Returns the first key-value pair.</p>
<b>Signature:</b>
```go
func (om *OrderedMap[K, V]) Front() (struct {
Key K
Value V
}, bool)
```
<b>Example:<span style="float:right;display:inline-block;">[Run]()</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
om := maputil.NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
frontElement, ok := om.Front()
fmt.Println(frontElement)
fmt.Println(ok)
// Output:
// {a 1}
// true
}
```
### <span id="OrderedMap_Back">OrderedMap_Back</span>
<p>Returns the last key-value pair.</p>
<b>Signature:</b>
```go
func (om *OrderedMap[K, V]) Back() (struct {
Key K
Value V
}, bool)
```
<b>Example:<span style="float:right;display:inline-block;">[Run]()</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
om := maputil.NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
frontElement, ok := om.Front()
fmt.Println(frontElement)
fmt.Println(ok)
// Output:
// {a 1}
// true
}
```
### <span id="OrderedMap_Range">OrderedMap_Range</span>
<p>Calls the given function for each key-value pair.</p>
<b>Signature:</b>
```go
func (om *OrderedMap[K, V]) Range(iteratee func(key K, value V) bool)
```
<b>Example:<span style="float:right;display:inline-block;">[Run]()</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
om := maputil.NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
om.Range(func(key string, value int) bool {
fmt.Println(key, value)
return true
})
// Output:
// a 1
// b 2
// c 3
}
```
### <span id="OrderedMap_Keys">OrderedMap_Keys</span>
<p>Returns the keys in order.</p>
<b>Signature:</b>
```go
func (om *OrderedMap[K, V]) Keys() []K
```
<b>Example:<span style="float:right;display:inline-block;">[Run]()</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
om := maputil.NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
keys := om.Keys()
fmt.Println(keys)
// Output:
// [a b c]
}
```
### <span id="OrderedMap_Values">OrderedMap_Values</span>
<p>Returns the values in order.</p>
<b>Signature:</b>
```go
func (om *OrderedMap[K, V]) Values() []V
```
<b>Example:<span style="float:right;display:inline-block;">[Run]()</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
om := maputil.NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
values := om.Values()
fmt.Println(values)
// Output:
// [1 2 3]
}
```
### <span id="OrderedMap_Elements">OrderedMap_Elements</span>
<p>Returns the key-value pairs in order.</p>
<b>Signature:</b>
```go
func (om *OrderedMap[K, V]) Elements() []struct
```
<b>Example:<span style="float:right;display:inline-block;">[Run]()</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
om := maputil.NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
elements := om.Elements()
fmt.Println(elements)
// Output:
// [{a 1} {b 2} {c 3}]
}
```
### <span id="OrderedMap_Len">OrderedMap_Len</span>
<p>Returns the number of key-value pairs.</p>
<b>Signature:</b>
```go
func (om *OrderedMap[K, V]) Len() int
```
<b>Example:<span style="float:right;display:inline-block;">[Run]()</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
om := maputil.NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
om.Len()
fmt.Println(om.Len())
// Output:
// 3
}
```
### <span id="OrderedMap_Contains">OrderedMap_Contains</span>
<p>Returns true if the given key exists.</p>
<b>Signature:</b>
```go
func (om *OrderedMap[K, V]) Contains(key K) bool
```
<b>Example:<span style="float:right;display:inline-block;">[Run]()</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
om := maputil.NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
result1 := om.Contains("a")
result2 := om.Contains("d")
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}
```
### <span id="OrderedMap_Iter">OrderedMap_Iter</span>
<p>Returns a channel that yields key-value pairs in order.</p>
<b>Signature:</b>
```go
func (om *OrderedMap[K, V]) Iter() <-chan struct {
Key K
Value V
}
```
<b>Example:<span style="float:right;display:inline-block;">[Run]()</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
om := maputil.NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
for elem := range om.Iter() {
fmt.Println(elem)
}
// Output:
// {a 1}
// {b 2}
// {c 3}
}
```
### <span id="OrderedMap_ReverseIter">OrderedMap_ReverseIter</span>
<p>Returns a channel that yields key-value pairs in reverse order.</p>
<b>Signature:</b>
```go
func (om *OrderedMap[K, V]) ReverseIter() <-chan struct {
Key K
Value V
}
```
<b>Example:<span style="float:right;display:inline-block;">[Run]()</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
om := maputil.NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
for elem := range om.ReverseIter() {
fmt.Println(elem)
}
// Output:
// {c 3}
// {b 2}
// {a 1}
}
```
### <span id="OrderedMap_SortByKey">OrderedMap_SortByKey</span>
<p>Sorts the map by key given less function.</p>
<b>Signature:</b>
```go
func (om *OrderedMap[K, V]) SortByKey(less func(a, b K) bool)
```
<b>Example:<span style="float:right;display:inline-block;">[Run]()</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
om := maputil.NewOrderedMap[string, int]()
om.Set(3, "c")
om.Set(1, "a")
om.Set(4, "d")
om.Set(2, "b")
om.SortByKey(func(a, b int) bool {
return a < b
})
fmt.Println(om.Elements())
// Output:
// [{1 a} {2 b} {3 c} {4 d}]
}
```
### <span id="OrderedMap_MarshalJSON">OrderedMap_MarshalJSON</span>
<p>Implements the json.Marshaler interface.</p>
<b>Signature:</b>
```go
func (om *OrderedMap[K, V]) MarshalJSON() ([]byte, error)
```
<b>Example:<span style="float:right;display:inline-block;">[Run]()</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
om := maputil.NewOrderedMap[string, int]()
om.Set(3, "c")
om.Set(1, "a")
om.Set(4, "d")
om.Set(2, "b")
b, _ := om.MarshalJSON()
fmt.Println(string(b))
// Output:
// {"a":1,"b":2,"c":3}
}
```
### <span id="OrderedMap_UnmarshalJSON">OrderedMap_UnmarshalJSON</span>
<p>Implements the json.Unmarshaler interface.</p>
<b>Signature:</b>
```go
func (om *OrderedMap[K, V]) UnmarshalJSON(data []byte) error
```
<b>Example:<span style="float:right;display:inline-block;">[Run]()</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
om := maputil.NewOrderedMap[string, int]()
data := []byte(`{"a":1,"b":2,"c":3}`)
om.UnmarshalJSON(data)
fmt.Println(om.Elements())
// Output:
}
```
@@ -1538,4 +2239,41 @@ func main() {
// a
// b
}
```
### <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 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>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m := map[int]string{
3: "c",
1: "a",
4: "d",
2: "b",
}
result := maputil.SortByKey(m)
fmt.Println(result)
// Output:
// map[1:a 2:b 3:c 4:d]
}
```

View File

@@ -242,7 +242,8 @@ func main() {
### <span id="ExecCommand">ExecCommand</span>
<p>Execute shell command, return the stdout and stderr string of command, and error if error occur. param `command` is a complete command string, like, ls -a (linux), dir(windows), ping 127.0.0.1. In linux, use /bin/bash -c to execute command, In windows, use powershell.exe to execute command.</p>
<p>Execute shell command, return the stdout and stderr string of command, and error if error occur. param `command` is a complete command string, like, ls -a (linux), dir(windows), ping 127.0.0.1. In linux, use /bin/bash -c to execute command, In windows, use powershell.exe to execute command.
The second parameter of the function is the cmd option control parameter. The type is func(*exec.Cmd). You can set the cmd attribute through this parameter.</p>
<b>Signature:</b>
@@ -263,7 +264,9 @@ import (
func main() {
// linux or mac
stdout, stderr, err := system.ExecCommand("ls")
stdout, stderr, err := system.ExecCommand("ls", func(cmd *exec.Cmd) {
cmd.Dir = "/tmp"
})
fmt.Println("std out: ", stdout)
fmt.Println("std err: ", stderr)
assert.Equal("", stderr)

View File

@@ -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,
}
)

View File

@@ -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))

View File

@@ -453,3 +453,23 @@ func GetOrSet[K comparable, V any](m map[K]V, key K, value V) V {
return value
}
// SortByKey sorts the map by its keys and returns a new map with sorted keys.
// Play: todo
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 less(keys[i], keys[j])
})
sortedKeysMap = make(map[K]V, len(m))
for _, k := range keys {
sortedKeysMap[k] = m[k]
}
return
}

View File

@@ -540,3 +540,295 @@ func ExampleGetOrSet() {
// a
// b
}
func ExampleSortByKey() {
m := map[int]string{
3: "c",
1: "a",
4: "d",
2: "b",
}
result := SortByKey(m, func(a, b int) bool {
return a < b
})
fmt.Println(result)
// Output:
// map[1:a 2:b 3:c 4:d]
}
func ExampleOrderedMap_Set() {
om := NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
val1, ok := om.Get("a")
fmt.Println(val1, ok)
val2, ok := om.Get("d")
fmt.Println(val2, ok)
// Output:
// 1 true
// 0 false
}
func ExampleOrderedMap_Get() {
om := NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
val1, ok := om.Get("a")
fmt.Println(val1, ok)
val2, ok := om.Get("d")
fmt.Println(val2, ok)
// Output:
// 1 true
// 0 false
}
func ExampleOrderedMap_Front() {
om := NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
frontElement, ok := om.Front()
fmt.Println(frontElement)
fmt.Println(ok)
// Output:
// {a 1}
// true
}
func ExampleOrderedMap_Back() {
om := NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
backElement, ok := om.Back()
fmt.Println(backElement)
fmt.Println(ok)
// Output:
// {c 3}
// true
}
func ExampleOrderedMap_Delete() {
om := NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
om.Delete("b")
fmt.Println(om.Keys())
// Output:
// [a c]
}
func ExampleOrderedMap_Clear() {
om := NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
om.Clear()
fmt.Println(om.Keys())
// Output:
// []
}
func ExampleOrderedMap_Len() {
om := NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
om.Len()
fmt.Println(om.Len())
// Output:
// 3
}
func ExampleOrderedMap_Keys() {
om := NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
keys := om.Keys()
fmt.Println(keys)
// Output:
// [a b c]
}
func ExampleOrderedMap_Values() {
om := NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
values := om.Values()
fmt.Println(values)
// Output:
// [1 2 3]
}
func ExampleOrderedMap_Contains() {
om := NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
result1 := om.Contains("a")
result2 := om.Contains("d")
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}
func ExampleOrderedMap_Range() {
om := NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
om.Range(func(key string, value int) bool {
fmt.Println(key, value)
return true
})
// Output:
// a 1
// b 2
// c 3
}
func ExampleOrderedMap_Elements() {
om := NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
elements := om.Elements()
fmt.Println(elements)
// Output:
// [{a 1} {b 2} {c 3}]
}
func ExampleOrderedMap_Iter() {
om := NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
for elem := range om.Iter() {
fmt.Println(elem)
}
// Output:
// {a 1}
// {b 2}
// {c 3}
}
func ExampleOrderedMap_ReverseIter() {
om := NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
for elem := range om.ReverseIter() {
fmt.Println(elem)
}
// Output:
// {c 3}
// {b 2}
// {a 1}
}
func ExampleOrderedMap_SortByKey() {
om := NewOrderedMap[int, string]()
om.Set(3, "c")
om.Set(1, "a")
om.Set(4, "d")
om.Set(2, "b")
om.SortByKey(func(a, b int) bool {
return a < b
})
fmt.Println(om.Elements())
// Output:
// [{1 a} {2 b} {3 c} {4 d}]
}
func ExampleOrderedMap_MarshalJSON() {
om := NewOrderedMap[string, int]()
om.Set("a", 1)
om.Set("b", 2)
om.Set("c", 3)
b, _ := om.MarshalJSON()
fmt.Println(string(b))
// Output:
// {"a":1,"b":2,"c":3}
}
func ExampleOrderedMap_UnmarshalJSON() {
om := NewOrderedMap[string, int]()
data := []byte(`{"a":1,"b":2,"c":3}`)
om.UnmarshalJSON(data)
fmt.Println(om.Elements())
// Output:
// [{a 1} {b 2} {c 3}]
}

View File

@@ -707,3 +707,47 @@ func TestGetOrSet(t *testing.T) {
assert.Equal("a", result1)
assert.Equal("b", result2)
}
func TestSortByKey(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSortByKey")
m1 := map[int]string{
3: "c",
1: "a",
4: "d",
2: "b",
}
expected1 := map[int]string{
1: "a",
2: "b",
3: "c",
4: "d",
}
result1 := SortByKey(m1, func(a, b int) bool {
return a < b
})
assert.Equal(expected1, result1)
m2 := map[string]int{
"c": 3,
"a": 1,
"d": 4,
"b": 2,
}
expected2 := map[string]int{
"d": 4,
"c": 3,
"b": 2,
"a": 1,
}
result2 := SortByKey(m2, func(a, b string) bool {
return a > b
})
assert.Equal(expected2, result2)
}

431
maputil/orderedmap.go Normal file
View 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),
}
}
// Sets the given key-value pair.
// 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
View 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"))
}

View File

@@ -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) {