1
0
mirror of https://github.com/duke-git/lancet.git synced 2026-02-14 01:32:27 +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>** : 重试执行的函数。 - **<big>RetryFunc</big>** : 重试执行的函数。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/retry.md#RetryFunc)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/retry.md#RetryFunc)]
[[play](https://go.dev/play/p/nk2XRmagfVF)] [[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。 - **<big>RetryTimes</big>** : 设置重试次数,默认 5。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/retry.md#RetryTimes)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/retry.md#RetryTimes)]
[[play](https://go.dev/play/p/ssfVeU2SwLO)] [[play](https://go.dev/play/p/ssfVeU2SwLO)]

View File

@@ -47,6 +47,24 @@ import (
- [MapToStruct](#MapToStruct) - [MapToStruct](#MapToStruct)
- [ToSortedSlicesDefault](#ToSortedSlicesDefault) - [ToSortedSlicesDefault](#ToSortedSlicesDefault)
- [ToSortedSlicesWithComparator](#ToSortedSlicesWithComparator) - [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) - [NewConcurrentMap](#NewConcurrentMap)
- [ConcurrentMap_Get](#ConcurrentMap_Get) - [ConcurrentMap_Get](#ConcurrentMap_Get)
- [ConcurrentMap_Set](#ConcurrentMap_Set) - [ConcurrentMap_Set](#ConcurrentMap_Set)
@@ -56,6 +74,7 @@ import (
- [ConcurrentMap_Has](#ConcurrentMap_Has) - [ConcurrentMap_Has](#ConcurrentMap_Has)
- [ConcurrentMap_Range](#ConcurrentMap_Range) - [ConcurrentMap_Range](#ConcurrentMap_Range)
- [GetOrSet](#GetOrSet) - [GetOrSet](#GetOrSet)
- [SortByKey](#SortByKey)
<div STYLE="page-break-after: always;"></div> <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> ### <span id="NewConcurrentMap">NewConcurrentMap</span>
<p>ConcurrentMap协程安全的map结构。</p> <p>ConcurrentMap协程安全的map结构。</p>
@@ -1522,4 +2224,41 @@ func main() {
// a // a
// b // 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") return errors.New("error occurs")
} }
duration := retry.RetryDuration(time.Microsecond*50) duration := retry.RetryWithLinearBackoff(time.Microsecond*50)
retry.Retry(increaseNumber, retry.Retry(increaseNumber,
duration, duration,
@@ -116,7 +116,7 @@ func main() {
return errors.New("error occurs") return errors.New("error occurs")
} }
duration := retry.RetryDuration(time.Microsecond*50) duration := retry.RetryWithLinearBackoff(time.Microsecond*50)
err := retry.Retry(increaseNumber, duration) err := retry.Retry(increaseNumber, duration)
if err != nil { 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> ### <span id="Retry">Retry</span>
<p>重试执行函数retryFunc直到函数运行成功或被context停止</p> <p>重试执行函数retryFunc直到函数运行成功或被context停止</p>
@@ -251,7 +205,7 @@ func main() {
return errors.New("error occurs") return errors.New("error occurs")
} }
duration := retry.RetryDuration(time.Microsecond*50) duration := retry.RetryWithLinearBackoff(time.Microsecond*50)
err := retry.Retry(increaseNumber, duration) err := retry.Retry(increaseNumber, duration)
if err != nil { if err != nil {

View File

@@ -241,7 +241,8 @@ func main() {
### <span id="ExecCommand">ExecCommand</span> ### <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> <b>函数签名:</b>
@@ -262,7 +263,9 @@ import (
func main() { func main() {
// linux or mac // 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 out: ", stdout)
fmt.Println("std err: ", stderr) fmt.Println("std err: ", stderr)
assert.Equal("", stderr) assert.Equal("", stderr)

View File

@@ -47,6 +47,24 @@ import (
- [MapToStruct](#MapToStruct) - [MapToStruct](#MapToStruct)
- [ToSortedSlicesDefault](#ToSortedSlicesDefault) - [ToSortedSlicesDefault](#ToSortedSlicesDefault)
- [ToSortedSlicesWithComparator](#ToSortedSlicesWithComparator) - [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) - [NewConcurrentMap](#NewConcurrentMap)
- [ConcurrentMap_Get](#ConcurrentMap_Get) - [ConcurrentMap_Get](#ConcurrentMap_Get)
- [ConcurrentMap_Set](#ConcurrentMap_Set) - [ConcurrentMap_Set](#ConcurrentMap_Set)
@@ -1127,10 +1145,693 @@ func main() {
fmt.Println(values1) fmt.Println(values1)
// Output: // Output:
// [3 2 1] // [3 2 1]
// [c b a] // [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] // [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] // [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 // a
// b // 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> ### <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> <b>Signature:</b>
@@ -263,7 +264,9 @@ import (
func main() { func main() {
// linux or mac // 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 out: ", stdout)
fmt.Println("std err: ", stderr) fmt.Println("std err: ", stderr)
assert.Equal("", stderr) assert.Equal("", stderr)

View File

@@ -18,63 +18,63 @@ import (
// http://en.wikipedia.org/wiki/Binary_prefix // http://en.wikipedia.org/wiki/Binary_prefix
const ( const (
// Decimal // Decimal
UnitB = 1 unitB = 1
UnitKB = 1000 unitKB = 1000
UnitMB = 1000 * UnitKB unitMB = 1000 * unitKB
UnitGB = 1000 * UnitMB unitGB = 1000 * unitMB
UnitTB = 1000 * UnitGB unitTB = 1000 * unitGB
UnitPB = 1000 * UnitTB unitPB = 1000 * unitTB
UnitEB = 1000 * UnitPB unitEB = 1000 * unitPB
// Binary // Binary
UnitBiB = 1 unitBiB = 1
UnitKiB = 1024 unitKiB = 1024
UnitMiB = 1024 * UnitKiB unitMiB = 1024 * unitKiB
UnitGiB = 1024 * UnitMiB unitGiB = 1024 * unitMiB
UnitTiB = 1024 * UnitGiB unitTiB = 1024 * unitGiB
UnitPiB = 1024 * UnitTiB unitPiB = 1024 * unitTiB
UnitEiB = 1024 * UnitPiB unitEiB = 1024 * unitPiB
) )
// type byteUnitMap map[byte]int64 // type byteUnitMap map[byte]int64
var ( var (
decimalByteMap = map[string]uint64{ decimalByteMap = map[string]uint64{
"b": UnitB, "b": unitB,
"kb": UnitKB, "kb": unitKB,
"mb": UnitMB, "mb": unitMB,
"gb": UnitGB, "gb": unitGB,
"tb": UnitTB, "tb": unitTB,
"pb": UnitPB, "pb": unitPB,
"eb": UnitEB, "eb": unitEB,
// Without suffix // Without suffix
"": UnitB, "": unitB,
"k": UnitKB, "k": unitKB,
"m": UnitMB, "m": unitMB,
"g": UnitGB, "g": unitGB,
"t": UnitTB, "t": unitTB,
"p": UnitPB, "p": unitPB,
"e": UnitEB, "e": unitEB,
} }
binaryByteMap = map[string]uint64{ binaryByteMap = map[string]uint64{
"bi": UnitBiB, "bi": unitBiB,
"kib": UnitKiB, "kib": unitKiB,
"mib": UnitMiB, "mib": unitMiB,
"gib": UnitGiB, "gib": unitGiB,
"tib": UnitTiB, "tib": unitTiB,
"pib": UnitPiB, "pib": unitPiB,
"eib": UnitEiB, "eib": unitEiB,
// Without suffix // Without suffix
"": UnitBiB, "": unitBiB,
"ki": UnitKiB, "ki": unitKiB,
"mi": UnitMiB, "mi": unitMiB,
"gi": UnitGiB, "gi": unitGiB,
"ti": UnitTiB, "ti": unitTiB,
"pi": UnitPiB, "pi": unitPiB,
"ei": UnitEiB, "ei": unitEiB,
} }
) )

View File

@@ -15,11 +15,11 @@ func TestDecimalBytes(t *testing.T) {
assert.Equal("1.024KB", DecimalBytes(1024)) assert.Equal("1.024KB", DecimalBytes(1024))
assert.Equal("1.2346MB", DecimalBytes(1234567)) assert.Equal("1.2346MB", DecimalBytes(1234567))
assert.Equal("1.235MB", DecimalBytes(1234567, 3)) assert.Equal("1.235MB", DecimalBytes(1234567, 3))
assert.Equal("1.123GB", DecimalBytes(float64(1.123*UnitGB))) assert.Equal("1.123GB", DecimalBytes(float64(1.123*unitGB)))
assert.Equal("2.123TB", DecimalBytes(float64(2.123*UnitTB))) assert.Equal("2.123TB", DecimalBytes(float64(2.123*unitTB)))
assert.Equal("3.123PB", DecimalBytes(float64(3.123*UnitPB))) assert.Equal("3.123PB", DecimalBytes(float64(3.123*unitPB)))
assert.Equal("4.123EB", DecimalBytes(float64(4.123*UnitEB))) assert.Equal("4.123EB", DecimalBytes(float64(4.123*unitEB)))
assert.Equal("1EB", DecimalBytes(float64(1000*UnitPB))) assert.Equal("1EB", DecimalBytes(float64(1000*unitPB)))
assert.Equal("62MB", DecimalBytes(61812496, 0)) assert.Equal("62MB", DecimalBytes(61812496, 0))
assert.Equal("61.8MB", DecimalBytes(61812496, 1)) assert.Equal("61.8MB", DecimalBytes(61812496, 1))
assert.Equal("401MB", DecimalBytes(401000000)) 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 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 // a
// b // 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("a", result1)
assert.Equal("b", result2) 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 := internal.NewAssert(t, "TestContain")
assert.Equal(true, Contain([]string{"a", "b", "c"}, "a")) tests := []struct {
assert.Equal(false, Contain([]string{"a", "b", "c"}, "d")) slice []string
assert.Equal(true, Contain([]string{""}, "")) give string
assert.Equal(false, Contain([]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) { func TestContainBy(t *testing.T) {
@@ -30,32 +38,53 @@ func TestContainBy(t *testing.T) {
assert := internal.NewAssert(t, "TestContainBy") assert := internal.NewAssert(t, "TestContainBy")
type foo struct { type foo struct {
A string a string
B int b int
} }
array1 := []foo{{A: "1", B: 1}, {A: "2", B: 2}} tests := []struct {
result1 := ContainBy(array1, func(f foo) bool { return f.A == "1" && f.B == 1 }) slice []foo
result2 := ContainBy(array1, func(f foo) bool { return f.A == "2" && f.B == 1 }) 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"} for _, tt := range tests {
result3 := ContainBy(array2, func(t string) bool { return t == "a" }) assert.Equal(tt.want, ContainBy(tt.slice, tt.predicateFn))
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)
} }
func TestContainSubSlice(t *testing.T) { func TestContainSubSlice(t *testing.T) {
t.Parallel() t.Parallel()
assert := internal.NewAssert(t, "TestContainSubSlice") 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"})) tests := []struct {
assert.Equal(true, ContainSubSlice([]int{1, 2, 3}, []int{1, 2})) slice []string
assert.Equal(false, ContainSubSlice([]int{1, 2, 3}, []int{0, 1})) 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) { func TestChunk(t *testing.T) {
@@ -63,29 +92,24 @@ func TestChunk(t *testing.T) {
assert := internal.NewAssert(t, "TestChunk") 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)) for _, tt := range tests {
assert.Equal(tt.want, Chunk(tt.slice, tt.chuanSize))
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))
} }
func TestCompact(t *testing.T) { func TestCompact(t *testing.T) {
@@ -134,6 +158,7 @@ func TestEqual(t *testing.T) {
assert.Equal(true, Equal(slice1, slice2)) assert.Equal(true, Equal(slice1, slice2))
assert.Equal(false, Equal(slice1, slice3)) assert.Equal(false, Equal(slice1, slice3))
assert.Equal(false, Equal(slice2, slice3))
} }
// go test -fuzz=Fuzz -fuzztime=10s . // go test -fuzz=Fuzz -fuzztime=10s .
@@ -163,12 +188,27 @@ func TestEvery(t *testing.T) {
assert := internal.NewAssert(t, "TestEvery") assert := internal.NewAssert(t, "TestEvery")
nums := []int{1, 2, 3, 5}
isEven := func(i, num int) bool { isEven := func(i, num int) bool {
return num%2 == 0 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) { func TestNone(t *testing.T) {
@@ -176,12 +216,27 @@ func TestNone(t *testing.T) {
assert := internal.NewAssert(t, "TestNone") assert := internal.NewAssert(t, "TestNone")
nums := []int{1, 2, 3, 5} isEven := func(i, num int) bool {
check := func(i, num int) bool { return num%2 == 0
}
isOdd := func(i, num int) bool {
return num%2 == 1 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) { func TestSome(t *testing.T) {
@@ -189,12 +244,27 @@ func TestSome(t *testing.T) {
assert := internal.NewAssert(t, "TestSome") assert := internal.NewAssert(t, "TestSome")
nums := []int{1, 2, 3, 5} isEven := func(i, num int) bool {
hasEven := func(i, num int) bool {
return num%2 == 0 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) { func TestFilter(t *testing.T) {
@@ -202,33 +272,37 @@ func TestFilter(t *testing.T) {
assert := internal.NewAssert(t, "TestFilter") assert := internal.NewAssert(t, "TestFilter")
nums := []int{1, 2, 3, 4, 5} t.Run("filter int slice", func(t *testing.T) {
isEven := func(i, num int) bool { nums := []int{1, 2, 3, 4, 5}
return num%2 == 0 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 { t.Run("filter struct slice", func(t *testing.T) {
name string type student struct {
age int name string
} age int
students := []student{ }
{"a", 10}, students := []student{
{"b", 11}, {"a", 10},
{"c", 12}, {"b", 11},
{"d", 13}, {"c", 12},
{"e", 14}, {"d", 13},
} {"e", 14},
studentsOfAageGreat12 := []student{ }
{"d", 13}, studentsOfAgeGreat12 := []student{
{"e", 14}, {"d", 13},
} {"e", 14},
filterFunc := func(i int, s student) bool { }
return s.age > 12 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) { func TestGroupBy(t *testing.T) {
@@ -249,6 +323,8 @@ func TestGroupBy(t *testing.T) {
func TestGroupWith(t *testing.T) { func TestGroupWith(t *testing.T) {
t.Parallel() t.Parallel()
assert := internal.NewAssert(t, "TestGroupWith")
nums := []float64{6.1, 4.2, 6.3} nums := []float64{6.1, 4.2, 6.3}
floor := func(num float64) float64 { floor := func(num float64) float64 {
return math.Floor(num) return math.Floor(num)
@@ -257,9 +333,8 @@ func TestGroupWith(t *testing.T) {
4: {4.2}, 4: {4.2},
6: {6.1, 6.3}, 6: {6.1, 6.3},
} }
actual := GroupWith(nums, floor)
assert := internal.NewAssert(t, "TestGroupWith") assert.Equal(expected, GroupWith(nums, floor))
assert.Equal(expected, actual)
} }
func TestCount(t *testing.T) { func TestCount(t *testing.T) {
@@ -295,8 +370,15 @@ func TestFind(t *testing.T) {
result, ok := Find(nums, even) result, ok := Find(nums, even)
assert := internal.NewAssert(t, "TestFind") assert := internal.NewAssert(t, "TestFind")
assert.Equal(true, ok) assert.Equal(true, ok)
assert.Equal(2, *result) assert.Equal(2, *result)
_, ok = Find(nums, func(_ int, v int) bool {
return v == 6
})
assert.Equal(false, ok)
} }
func TestFindBy(t *testing.T) { func TestFindBy(t *testing.T) {
@@ -358,19 +440,6 @@ func TestFindLast(t *testing.T) {
assert.Equal(4, *result) 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) { func TestFlatten(t *testing.T) {
t.Parallel() 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 { result1 := ReduceBy([]int{1, 2, 3, 4}, 0, func(_ int, item int, agg int) int {
return agg + item return agg + item
}) })
assert.Equal(10, result1)
result2 := ReduceBy([]int{1, 2, 3, 4}, "", func(_ int, item int, agg string) string { result2 := ReduceBy([]int{1, 2, 3, 4}, "", func(_ int, item int, agg string) string {
return agg + fmt.Sprintf("%v", item) return agg + fmt.Sprintf("%v", item)
}) })
assert.Equal(10, result1)
assert.Equal("1234", result2) assert.Equal("1234", result2)
} }
func TestReduceRight(t *testing.T) { func TestReduceRight(t *testing.T) {
@@ -692,15 +759,23 @@ func TestDeleteAt(t *testing.T) {
t.Parallel() t.Parallel()
assert := internal.NewAssert(t, "TestDeleteAt") assert := internal.NewAssert(t, "TestDeleteAt")
arr := []int{1, 2, 3, 4, 5}
assert.Equal([]int{2, 3, 4, 5}, DeleteAt(arr, 0)) tests := []struct {
assert.Equal([]int{1, 2, 3, 4}, DeleteAt(arr, 4)) 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)) for _, tt := range tests {
assert.Equal([]int{1, 2, 3, 4}, DeleteAt(arr, 6)) assert.Equal(tt.wang, DeleteAt(tt.slice, tt.deletePos))
}
assert.Equal([]int{1, 2, 3, 4, 5}, arr)
} }
func TestDeleteRange(t *testing.T) { func TestDeleteRange(t *testing.T) {
@@ -720,16 +795,24 @@ func TestDrop(t *testing.T) {
assert := internal.NewAssert(t, "TestDrop") assert := internal.NewAssert(t, "TestDrop")
assert.Equal([]int{}, Drop([]int{}, 0)) tests := []struct {
assert.Equal([]int{}, Drop([]int{}, 1)) slice []int
assert.Equal([]int{}, Drop([]int{}, -1)) 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)) for _, tt := range tests {
assert.Equal([]int{2, 3, 4, 5}, Drop([]int{1, 2, 3, 4, 5}, 1)) assert.Equal(tt.want, Drop(tt.slice, tt.dropNum))
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))
} }
func TestDropRight(t *testing.T) { func TestDropRight(t *testing.T) {
@@ -737,16 +820,23 @@ func TestDropRight(t *testing.T) {
assert := internal.NewAssert(t, "TestDropRight") assert := internal.NewAssert(t, "TestDropRight")
assert.Equal([]int{}, DropRight([]int{}, 0)) tests := []struct {
assert.Equal([]int{}, DropRight([]int{}, 1)) slice []int
assert.Equal([]int{}, DropRight([]int{}, -1)) dropNum int
want []int
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)) {[]int{}, 0, []int{}},
assert.Equal([]int{}, DropRight([]int{1, 2, 3, 4, 5}, 5)) {[]int{}, 1, []int{}},
assert.Equal([]int{}, DropRight([]int{1, 2, 3, 4, 5}, 6)) {[]int{}, -1, []int{}},
{[]int{1, 2, 3, 4, 5}, -1, []int{1, 2, 3, 4, 5}},
assert.Equal([]int{1, 2, 3, 4, 5}, DropRight([]int{1, 2, 3, 4, 5}, -1)) {[]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) { func TestDropWhile(t *testing.T) {
@@ -754,22 +844,19 @@ func TestDropWhile(t *testing.T) {
assert := internal.NewAssert(t, "TestDropWhile") 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 { for _, tt := range tests {
return n != 2 assert.Equal(tt.want, DropWhile(tt.slice, tt.fn))
}) }
assert.Equal([]int{2, 3, 4, 5}, r1)
r2 := DropWhile(numbers, func(n int) bool {
return true
})
assert.Equal([]int{}, r2)
r3 := DropWhile(numbers, func(n int) bool {
return n == 0
})
assert.Equal([]int{1, 2, 3, 4, 5}, r3)
} }
func TestDropRightWhile(t *testing.T) { func TestDropRightWhile(t *testing.T) {
@@ -777,22 +864,19 @@ func TestDropRightWhile(t *testing.T) {
assert := internal.NewAssert(t, "TestDropRightWhile") 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 { for _, tt := range tests {
return n != 2 assert.Equal(tt.want, DropRightWhile(tt.slice, tt.fn))
}) }
assert.Equal([]int{1, 2}, r1)
r2 := DropRightWhile(numbers, func(n int) bool {
return true
})
assert.Equal([]int{}, r2)
r3 := DropRightWhile(numbers, func(n int) bool {
return n == 0
})
assert.Equal([]int{1, 2, 3, 4, 5}, r3)
} }
func TestInsertAt(t *testing.T) { func TestInsertAt(t *testing.T) {
@@ -800,15 +884,25 @@ func TestInsertAt(t *testing.T) {
assert := internal.NewAssert(t, "TestInsertAt") assert := internal.NewAssert(t, "TestInsertAt")
strs := []string{"a", "b", "c"} tests := []struct {
assert.Equal([]string{"a", "b", "c"}, InsertAt(strs, -1, "1")) slice []string
assert.Equal([]string{"a", "b", "c"}, InsertAt(strs, 4, "1")) insertPos int
assert.Equal([]string{"1", "a", "b", "c"}, InsertAt(strs, 0, "1")) insertValue any
assert.Equal([]string{"a", "1", "b", "c"}, InsertAt(strs, 1, "1")) want []string
assert.Equal([]string{"a", "b", "1", "c"}, InsertAt(strs, 2, "1")) }{
assert.Equal([]string{"a", "b", "c", "1"}, InsertAt(strs, 3, "1")) {[]string{"a", "b", "c"}, -1, "1", []string{"a", "b", "c"}},
assert.Equal([]string{"1", "2", "3", "a", "b", "c"}, InsertAt(strs, 0, []string{"1", "2", "3"})) {[]string{"a", "b", "c"}, 4, "1", []string{"a", "b", "c"}},
assert.Equal([]string{"a", "b", "c", "1", "2", "3"}, InsertAt(strs, 3, []string{"1", "2", "3"})) {[]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) { func TestUpdateAt(t *testing.T) {