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:
@@ -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)]
|
||||
|
||||
@@ -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]
|
||||
}
|
||||
```
|
||||
@@ -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 {
|
||||
|
||||
@@ -241,7 +241,8 @@ func main() {
|
||||
|
||||
### <span id="ExecCommand">ExecCommand</span>
|
||||
|
||||
<p>执行shell命令,返回命令的stdout和stderr字符串,如果出现错误,则返回错误。参数`command`是一个完整的命令字符串,如ls-a(linux),dir(windows),ping 127.0.0.1。在linux中,使用/bin/bash-c执行命令,在windows中,使用powershell.exe执行命令。</p>
|
||||
<p>执行shell命令,返回命令的stdout和stderr字符串,如果出现错误,则返回错误。参数`command`是一个完整的命令字符串,如ls-a(linux),dir(windows),ping 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)
|
||||
|
||||
@@ -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]
|
||||
}
|
||||
```
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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}]
|
||||
}
|
||||
|
||||
@@ -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
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),
|
||||
}
|
||||
}
|
||||
|
||||
// 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
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