mirror of
https://github.com/duke-git/lancet.git
synced 2026-02-04 21:02:27 +08:00
Compare commits
91 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9aa3b742ff | ||
|
|
6bfaba750d | ||
|
|
69f8bee935 | ||
|
|
07d04a9cd0 | ||
|
|
6f17ba9116 | ||
|
|
56d1e5e95c | ||
|
|
11d86d0270 | ||
|
|
d1c20a1da8 | ||
|
|
f87ab89207 | ||
|
|
9ebb0c7920 | ||
|
|
31a5ed11a3 | ||
|
|
a706d488e6 | ||
|
|
61251fb0f1 | ||
|
|
747dc30b02 | ||
|
|
d54f27d9a9 | ||
|
|
dbca2f6be4 | ||
|
|
2ef9b56d22 | ||
|
|
52ecde7e24 | ||
|
|
a7dce5e4d3 | ||
|
|
4718da44f4 | ||
|
|
1aa1f95524 | ||
|
|
d922b2e778 | ||
|
|
5a7b3c4a37 | ||
|
|
1c2b1a2f02 | ||
|
|
c68440ecf8 | ||
|
|
6a48b3f99e | ||
|
|
bab9ae32d4 | ||
|
|
f0e6e94c5e | ||
|
|
a6fe155781 | ||
|
|
d5be9009fc | ||
|
|
ca47be41f6 | ||
|
|
ff5db30208 | ||
|
|
a429d46072 | ||
|
|
7b84fbfd94 | ||
|
|
fc6f618885 | ||
|
|
7f03c3b0a2 | ||
|
|
4b4386bd47 | ||
|
|
10a1706613 | ||
|
|
d097f356fd | ||
|
|
bc9bacaa55 | ||
|
|
c949059fb1 | ||
|
|
9c6d489db7 | ||
|
|
45436798af | ||
|
|
bd0eb0682c | ||
|
|
bdbc06b095 | ||
|
|
2f504ce851 | ||
|
|
02a24b461c | ||
|
|
3f7a81c005 | ||
|
|
cc6e10ee5a | ||
|
|
eff2f22440 | ||
|
|
47b6747bb0 | ||
|
|
298219aee7 | ||
|
|
d5607b0a5a | ||
|
|
f47873fbc7 | ||
|
|
f24ad26692 | ||
|
|
88de9bfac2 | ||
|
|
e4777a0986 | ||
|
|
84a69d1fa5 | ||
|
|
5eb056277d | ||
|
|
4e6d586251 | ||
|
|
61c7012e17 | ||
|
|
0d48778886 | ||
|
|
e98c46c903 | ||
|
|
155f287ab0 | ||
|
|
652916b7d7 | ||
|
|
955de2bdbf | ||
|
|
a4c1d40faa | ||
|
|
f155e0caa6 | ||
|
|
fb0332449c | ||
|
|
68f0fd1d4c | ||
|
|
70995c5098 | ||
|
|
55e62ed8ca | ||
|
|
e614274f07 | ||
|
|
c524eb04a1 | ||
|
|
985b3cddd8 | ||
|
|
abadeec007 | ||
|
|
3ab05154aa | ||
|
|
9f1c89bf0e | ||
|
|
9444582e44 | ||
|
|
c27ccad2b9 | ||
|
|
d1c6c57700 | ||
|
|
922999037f | ||
|
|
046e90486d | ||
|
|
fc6dee9e77 | ||
|
|
980ff2c363 | ||
|
|
763aa8e10d | ||
|
|
83c0d1d6e6 | ||
|
|
dfc6b868fb | ||
|
|
f66c0938e5 | ||
|
|
a4900fecb4 | ||
|
|
dc25bdab2f |
83
README.md
83
README.md
@@ -4,7 +4,7 @@
|
||||
<br/>
|
||||
|
||||

|
||||
[](https://github.com/duke-git/lancet/releases)
|
||||
[](https://github.com/duke-git/lancet/releases)
|
||||
[](https://pkg.go.dev/github.com/duke-git/lancet/v2)
|
||||
[](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
|
||||
[](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
|
||||
@@ -23,7 +23,7 @@ English | [简体中文](./README_zh-CN.md)
|
||||
## Feature
|
||||
|
||||
- 👏 Comprehensive, efficient and reusable.
|
||||
- 💪 250+ go util functions, support string, slice, datetime, net, crypt...
|
||||
- 💪 300+ go util functions, support string, slice, datetime, net, crypt...
|
||||
- 💅 Only depend on the go standard library.
|
||||
- 🌍 Unit test for every exported function.
|
||||
|
||||
@@ -69,7 +69,7 @@ func main() {
|
||||
|
||||
## API Documentation
|
||||
|
||||
### Algorithm package implements some basic algorithm. eg. sort, search.
|
||||
### 1. Algorithm package implements some basic algorithm. eg. sort, search.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/algorithm"
|
||||
@@ -89,7 +89,25 @@ import "github.com/duke-git/lancet/v2/algorithm"
|
||||
- [LRUCache](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#LRUCache)
|
||||
|
||||
|
||||
### Convertor package contains some functions for data convertion.
|
||||
|
||||
### 2. Concurrency package contain some functions to support concurrent programming. eg, goroutine, channel, async.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/concurrency"
|
||||
```
|
||||
#### Function list:
|
||||
- [NewChannel](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#NewChannel)
|
||||
- [Bridge](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Bridge)
|
||||
- [FanIn](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#FanIn)
|
||||
- [Generate](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Generate)
|
||||
- [Or](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Or)
|
||||
- [OrDone](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#OrDone)
|
||||
- [Repeat](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Repeat)
|
||||
- [RepeatFn](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#RepeatFn)
|
||||
- [Take](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Take)
|
||||
- [Tee](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Tee)
|
||||
|
||||
### 3. Convertor package contains some functions for data convertion.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/convertor"
|
||||
@@ -105,7 +123,7 @@ import "github.com/duke-git/lancet/v2/convertor"
|
||||
- [ToString](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToString)
|
||||
- [StructToMap](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#StructToMap)
|
||||
|
||||
### Cryptor package is for data encryption and decryption.
|
||||
### 4. Cryptor package is for data encryption and decryption.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/cryptor"
|
||||
@@ -145,7 +163,7 @@ import "github.com/duke-git/lancet/v2/cryptor"
|
||||
- [RsaEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#RsaEncrypt)
|
||||
- [RsaDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#RsaDecrypt)
|
||||
|
||||
### Datetime package supports date and time format and compare.
|
||||
### 5. Datetime package supports date and time format and compare.
|
||||
|
||||
|
||||
```go
|
||||
@@ -183,7 +201,29 @@ import "github.com/duke-git/lancet/v2/datetime"
|
||||
- [ToFormatForTpl](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#ToFormatForTpl)
|
||||
- [ToIso8601](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#ToIso8601)
|
||||
|
||||
### Fileutil package implements some basic functions for file operations.
|
||||
|
||||
|
||||
### 6. Datastructure package constains some common data structure. eg. list, linklist, stack, queue, set, tree, graph.
|
||||
|
||||
|
||||
```go
|
||||
import list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
import link "github.com/duke-git/lancet/v2/datastructure/link"
|
||||
import stack "github.com/duke-git/lancet/v2/datastructure/stack"
|
||||
import queue "github.com/duke-git/lancet/v2/datastructure/queue"
|
||||
import set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||
import tree "github.com/duke-git/lancet/v2/datastructure/tree"
|
||||
```
|
||||
#### Function list:
|
||||
- [List](https://github.com/duke-git/lancet/blob/main/docs/datastructure/list.md)
|
||||
- [Linklist](https://github.com/duke-git/lancet/blob/main/docs/datastructure/linklist.md)
|
||||
- [Stack](https://github.com/duke-git/lancet/blob/main/docs/datastructure/stack.md)
|
||||
- [Queue](https://github.com/duke-git/lancet/blob/main/docs/datastructure/queue.md)
|
||||
- [Set](https://github.com/duke-git/lancet/blob/main/docs/datastructure/set.md)
|
||||
- [Tree](https://github.com/duke-git/lancet/blob/main/docs/datastructure/tree.md)
|
||||
|
||||
|
||||
### 7. Fileutil package implements some basic functions for file operations.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/fileutil"
|
||||
@@ -206,7 +246,7 @@ import "github.com/duke-git/lancet/v2/fileutil"
|
||||
- [Zip](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#Zip)
|
||||
- [UnZip](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#UnZip)
|
||||
|
||||
### Formatter contains some functions for data formatting.
|
||||
### 8. Formatter contains some functions for data formatting.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/formatter"
|
||||
@@ -214,7 +254,7 @@ import "github.com/duke-git/lancet/v2/formatter"
|
||||
#### Function list:
|
||||
- [Comma](https://github.com/duke-git/lancet/blob/main/docs/formatter.md#Comma)
|
||||
|
||||
### Function package can control the flow of function execution and support part of functional programming
|
||||
### 9. Function package can control the flow of function execution and support part of functional programming
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/function"
|
||||
@@ -230,7 +270,7 @@ import "github.com/duke-git/lancet/v2/function"
|
||||
- [Watcher](https://github.com/duke-git/lancet/blob/main/docs/function.md#Watcher)
|
||||
|
||||
|
||||
### Maputil package includes some functions to manipulate map.
|
||||
### 10. Maputil package includes some functions to manipulate map.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/maputil"
|
||||
@@ -246,7 +286,7 @@ import "github.com/duke-git/lancet/v2/maputil"
|
||||
- [Values](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Values)
|
||||
|
||||
|
||||
### Mathutil package implements some functions for math calculation.
|
||||
### 11. Mathutil package implements some functions for math calculation.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/mathutil"
|
||||
@@ -258,14 +298,16 @@ import "github.com/duke-git/lancet/v2/mathutil"
|
||||
- [Fibonacci](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Fibonacci)
|
||||
- [Factorial](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Factorial)
|
||||
- [Max](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Max)
|
||||
- [MaxBy](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#MaxBy)
|
||||
- [Min](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Min)
|
||||
- [MinBy](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#MinBy)
|
||||
- [Percent](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Percent)
|
||||
- [RoundToFloat](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#RoundToFloat)
|
||||
- [RoundToString](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#RoundToString)
|
||||
- [TruncRound](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#TruncRound)
|
||||
|
||||
|
||||
### Netutil package contains functions to get net information and send http request.
|
||||
### 12. Netutil package contains functions to get net information and send http request.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/netutil"
|
||||
@@ -285,7 +327,7 @@ import "github.com/duke-git/lancet/v2/netutil"
|
||||
- [HttpPatch](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpPatch)
|
||||
- [ParseHttpResponse](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#ParseHttpResponse)
|
||||
|
||||
### Random package implements some basic functions to generate random int and string.
|
||||
### 13. Random package implements some basic functions to generate random int and string.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/random"
|
||||
@@ -297,7 +339,7 @@ import "github.com/duke-git/lancet/v2/random"
|
||||
- [RandString](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandString)
|
||||
- [UUIdV4](https://github.com/duke-git/lancet/blob/main/docs/random.md#UUIdV4)
|
||||
|
||||
### Retry package is for executing a function repeatedly until it was successful or canceled by the context.
|
||||
### 14. Retry package is for executing a function repeatedly until it was successful or canceled by the context.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/retry"
|
||||
@@ -310,7 +352,7 @@ import "github.com/duke-git/lancet/v2/retry"
|
||||
- [RetryDuration](https://github.com/duke-git/lancet/blob/main/docs/retry.md#RetryDuration)
|
||||
- [RetryTimes](https://github.com/duke-git/lancet/blob/main/docs/retry.md#RetryTimes)
|
||||
|
||||
### Slice contains some functions to manipulate slice.
|
||||
### 15. Slice contains some functions to manipulate slice.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/slice"
|
||||
@@ -340,6 +382,8 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
- [InterfaceSlice](https://github.com/duke-git/lancet/blob/main/docs/slice.md#InterfaceSlice)
|
||||
- [Intersection](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Intersection)
|
||||
- [InsertAt](https://github.com/duke-git/lancet/blob/main/docs/slice.md#InsertAt)
|
||||
- [IndexOf](https://github.com/duke-git/lancet/blob/main/docs/slice.md#IndexOf)
|
||||
- [LastIndexOf](https://github.com/duke-git/lancet/blob/main/docs/slice.md#LastIndexOf)
|
||||
- [Map](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Map)
|
||||
- [Reverse](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Reverse)
|
||||
- [Reduce](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Reduce)
|
||||
@@ -353,7 +397,7 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
- [UpdateAt](https://github.com/duke-git/lancet/blob/main/docs/slice.md#UpdateAt)
|
||||
- [Without](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Without)
|
||||
|
||||
### Strutil package contains some functions to manipulate string.
|
||||
### 16. Strutil package contains some functions to manipulate string.
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/strutil"
|
||||
```
|
||||
@@ -374,10 +418,11 @@ import "github.com/duke-git/lancet/v2/strutil"
|
||||
- [PadStart](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#PadStart)
|
||||
- [ReverseStr](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#ReverseStr)
|
||||
- [SnakeCase](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#SnakeCase)
|
||||
- [SplitEx](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#SplitEx)
|
||||
- [Wrap](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Wrap)
|
||||
- [Unwrap](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Unwrap)
|
||||
|
||||
### System package contain some functions about os, runtime, shell command.
|
||||
### 17. System package contain some functions about os, runtime, shell command.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/system"
|
||||
@@ -392,7 +437,7 @@ import "github.com/duke-git/lancet/v2/system"
|
||||
- [CompareOsEnv](https://github.com/duke-git/lancet/blob/main/docs/system.md#CompareOsEnv)
|
||||
- [ExecCommand](https://github.com/duke-git/lancet/blob/main/docs/system.md#ExecCommand)
|
||||
|
||||
### Validator package contains some functions for data validation.
|
||||
### 18. Validator package contains some functions for data validation.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/validator"
|
||||
@@ -426,7 +471,7 @@ import "github.com/duke-git/lancet/v2/validator"
|
||||
- [IsStrongPassword](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsStrongPassword)
|
||||
- [IsUrl](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsUrl)
|
||||
- [IsWeakPassword](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsWeakPassword)
|
||||
### xerror package implements helpers for errors.
|
||||
### 19. xerror package implements helpers for errors.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/xerror"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<br/>
|
||||
|
||||

|
||||
[](https://github.com/duke-git/lancet/releases)
|
||||
[](https://github.com/duke-git/lancet/releases)
|
||||
[](https://pkg.go.dev/github.com/duke-git/lancet/v2)
|
||||
[](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
|
||||
[](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
|
||||
@@ -23,7 +23,7 @@
|
||||
## 特性
|
||||
|
||||
- 👏 全面、高效、可复用
|
||||
- 💪 250+常用go工具函数,支持string、slice、datetime、net、crypt...
|
||||
- 💪 300+常用go工具函数,支持string、slice、datetime、net、crypt...
|
||||
- 💅 只依赖go标准库
|
||||
- 🌍 所有导出函数单元测试覆盖率100%
|
||||
|
||||
@@ -69,7 +69,7 @@ func main() {
|
||||
|
||||
## API文档
|
||||
|
||||
### algorithm算法包实现一些基本算法。eg. sort, search.
|
||||
### 1. algorithm算法包实现一些基本算法。eg. sort, search.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/algorithm"
|
||||
@@ -88,7 +88,25 @@ import "github.com/duke-git/lancet/v2/algorithm"
|
||||
- [LinearSearch](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#LinearSearch)
|
||||
- [LRUCache](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#LRUCache)
|
||||
|
||||
### convertor转换器包支持一些常见的数据类型转换。
|
||||
|
||||
### 2. 并发包包含一些支持并发编程的功能。例如:goroutine, channel, async等。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/concurrency"
|
||||
```
|
||||
#### Function list:
|
||||
- [NewChannel](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#NewChannel)
|
||||
- [Bridge](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Bridge)
|
||||
- [FanIn](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#FanIn)
|
||||
- [Generate](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Generate)
|
||||
- [Or](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Or)
|
||||
- [OrDone](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#OrDone)
|
||||
- [Repeat](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Repeat)
|
||||
- [RepeatFn](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#RepeatFn)
|
||||
- [Take](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Take)
|
||||
- [Tee](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Tee)
|
||||
|
||||
### 3. convertor转换器包支持一些常见的数据类型转换。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/convertor"
|
||||
@@ -104,7 +122,7 @@ import "github.com/duke-git/lancet/v2/convertor"
|
||||
- [ToString](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToString)
|
||||
- [StructToMap](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#StructToMap)
|
||||
|
||||
### cryptor加密包支持数据加密和解密,获取md5,hash值。支持base64, md5, hmac, aes, des, rsa。
|
||||
### 4. cryptor加密包支持数据加密和解密,获取md5,hash值。支持base64, md5, hmac, aes, des, rsa。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/cryptor"
|
||||
@@ -144,7 +162,7 @@ import "github.com/duke-git/lancet/v2/cryptor"
|
||||
- [RsaEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#RsaEncrypt)
|
||||
- [RsaDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#RsaDecrypt)
|
||||
|
||||
### datetime日期时间处理包,格式化日期,比较日期。
|
||||
### 5. datetime日期时间处理包,格式化日期,比较日期。
|
||||
|
||||
|
||||
```go
|
||||
@@ -182,7 +200,28 @@ import "github.com/duke-git/lancet/v2/datetime"
|
||||
- [ToFormatForTpl](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#ToFormatForTpl)
|
||||
- [ToIso8601](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#ToIso8601)
|
||||
|
||||
### fileutil包支持文件基本操作。
|
||||
|
||||
### 6. datastructure包含一些普通的数据结构实现。例如:list, linklist, stack, queue, set, tree, graph.
|
||||
|
||||
|
||||
```go
|
||||
import list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
import link "github.com/duke-git/lancet/v2/datastructure/link"
|
||||
import stack "github.com/duke-git/lancet/v2/datastructure/stack"
|
||||
import queue "github.com/duke-git/lancet/v2/datastructure/queue"
|
||||
import set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||
import tree "github.com/duke-git/lancet/v2/datastructure/tree"
|
||||
```
|
||||
#### Function list:
|
||||
- [List](https://github.com/duke-git/lancet/blob/main/docs/datastructure/list_zh-CN.md)
|
||||
- [Linklist](https://github.com/duke-git/lancet/blob/main/docs/datastructure/linklist_zh-CN.md)
|
||||
- [Stack](https://github.com/duke-git/lancet/blob/main/docs/datastructure/stack_zh-CN.md)
|
||||
- [Queue](https://github.com/duke-git/lancet/blob/main/docs/datastructure/queue_zh-CN.md)
|
||||
- [Set](https://github.com/duke-git/lancet/blob/main/docs/datastructure/set_zh-CN.md)
|
||||
- [Tree](https://github.com/duke-git/lancet/blob/main/docs/datastructure/tree_zh-CN.md)
|
||||
|
||||
|
||||
### 7. fileutil包支持文件基本操作。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/fileutil"
|
||||
@@ -205,7 +244,7 @@ import "github.com/duke-git/lancet/v2/fileutil"
|
||||
- [Zip](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#Zip)
|
||||
- [UnZip](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#UnZip)
|
||||
|
||||
### formatter格式化器包含一些数据格式化处理方法。
|
||||
### 8. formatter格式化器包含一些数据格式化处理方法。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/formatter"
|
||||
@@ -214,7 +253,7 @@ import "github.com/duke-git/lancet/v2/formatter"
|
||||
- [Comma](https://github.com/duke-git/lancet/blob/main/docs/formatter_zh-CN.md#Comma)
|
||||
|
||||
|
||||
### function函数包控制函数执行流程,包含部分函数式编程。
|
||||
### 9. function函数包控制函数执行流程,包含部分函数式编程。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/function"
|
||||
@@ -230,7 +269,7 @@ import "github.com/duke-git/lancet/v2/function"
|
||||
- [Watcher](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Watcher)
|
||||
|
||||
|
||||
### maputil包包括一些操作map的函数.
|
||||
### 10. maputil包包括一些操作map的函数.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/maputil"
|
||||
@@ -245,7 +284,7 @@ import "github.com/duke-git/lancet/v2/maputil"
|
||||
- [Minus](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Minus)
|
||||
- [Values](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Values)
|
||||
|
||||
### mathutil包实现了一些数学计算的函数。
|
||||
### 11. mathutil包实现了一些数学计算的函数。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/mathutil"
|
||||
@@ -257,13 +296,15 @@ import "github.com/duke-git/lancet/v2/mathutil"
|
||||
- [Fibonacci](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Fibonacci)
|
||||
- [Factorial](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Factorial)
|
||||
- [Max](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Max)
|
||||
- [MaxBy](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#MaxBy)
|
||||
- [Min](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Min)
|
||||
- [MinBy](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#MinBy)
|
||||
- [Percent](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Percent)
|
||||
- [RoundToFloat](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#RoundToFloat)
|
||||
- [RoundToString](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#RoundToString)
|
||||
- [TruncRound](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#TruncRound)
|
||||
|
||||
### netutil网络包支持获取ip地址,发送http请求。
|
||||
### 12. netutil网络包支持获取ip地址,发送http请求。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/netutil"
|
||||
@@ -283,7 +324,7 @@ import "github.com/duke-git/lancet/v2/netutil"
|
||||
- [HttpPatch](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPatch)
|
||||
- [ParseHttpResponse](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#ParseHttpResponse)
|
||||
|
||||
### random随机数生成器包,可以生成随机[]bytes, int, string。
|
||||
### 13. random随机数生成器包,可以生成随机[]bytes, int, string。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/random"
|
||||
@@ -294,7 +335,7 @@ import "github.com/duke-git/lancet/v2/random"
|
||||
- [RandInt](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#RandInt)
|
||||
- [RandString](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#RandString)
|
||||
- [UUIdV4](https://github.com/duke-git/lancet/blob/main/docs/random.md#UUIdV4)
|
||||
### retry重试执行函数直到函数运行成功或被context cancel。
|
||||
### 14. retry重试执行函数直到函数运行成功或被context cancel。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/retry"
|
||||
@@ -308,7 +349,7 @@ import "github.com/duke-git/lancet/v2/retry"
|
||||
- [RetryTimes](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#RetryTimes)
|
||||
|
||||
|
||||
### slice包包含操作切片的方法集合。
|
||||
### 15. slice包包含操作切片的方法集合。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/slice"
|
||||
@@ -338,6 +379,8 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
- [InterfaceSlice](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#InterfaceSlice)
|
||||
- [Intersection](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Intersection)
|
||||
- [InsertAt](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#InsertAt)
|
||||
- [IndexOf](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#IndexOf)
|
||||
- [LastIndexOf](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#LastIndexOf)
|
||||
- [Map](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Map)
|
||||
- [Reverse](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Reverse)
|
||||
- [Reduce](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Reduce)
|
||||
@@ -352,7 +395,7 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
- [Without](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Without)
|
||||
|
||||
|
||||
### strutil包含处理字符串的相关函数。
|
||||
### 16. strutil包含处理字符串的相关函数。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/strutil"
|
||||
@@ -374,11 +417,12 @@ import "github.com/duke-git/lancet/v2/strutil"
|
||||
- [PadStart](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#PadStart)
|
||||
- [ReverseStr](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#ReverseStr)
|
||||
- [SnakeCase](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#SnakeCase)
|
||||
- [SplitEx](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#SplitEx)
|
||||
- [Wrap](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Wrap)
|
||||
- [Unwrap](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Unwrap)
|
||||
|
||||
|
||||
### system包含os, runtime, shell command相关函数。
|
||||
### 17. system包含os, runtime, shell command相关函数。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/system"
|
||||
@@ -394,7 +438,7 @@ import "github.com/duke-git/lancet/v2/system"
|
||||
- [CompareOsEnv](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN.md#CompareOsEnv)
|
||||
- [ExecCommand](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN.md#ExecCommand)
|
||||
|
||||
### validator验证器包,包含常用字符串格式验证函数。
|
||||
### 18. validator验证器包,包含常用字符串格式验证函数。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/validator"
|
||||
@@ -429,7 +473,7 @@ import "github.com/duke-git/lancet/v2/validator"
|
||||
- [IsWeakPassword](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsWeakPassword)
|
||||
|
||||
validator.md#IsWeakPassword)
|
||||
### xerror包实现一些错误处理函数
|
||||
### 19. xerror包实现一些错误处理函数
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/xerror"
|
||||
|
||||
243
concurrency/channel.go
Normal file
243
concurrency/channel.go
Normal file
@@ -0,0 +1,243 @@
|
||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package concurrency contain some functions to support concurrent programming. eg, goroutine, channel, async.
|
||||
package concurrency
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Channel is a logic object which can generate or manipulate go channel
|
||||
// all methods of Channel are in the book tilted《Concurrency in Go》
|
||||
type Channel struct {
|
||||
}
|
||||
|
||||
// NewChannel return a Channel instance
|
||||
func NewChannel() *Channel {
|
||||
return &Channel{}
|
||||
}
|
||||
|
||||
// Generate a data of type any chan, put param `values` into the chan
|
||||
func (c *Channel) Generate(ctx context.Context, values ...any) <-chan any {
|
||||
dataStream := make(chan any)
|
||||
|
||||
go func() {
|
||||
defer close(dataStream)
|
||||
|
||||
for _, v := range values {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case dataStream <- v:
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return dataStream
|
||||
}
|
||||
|
||||
// Repeat return a data of type any chan, put param `values` into the chan repeatly until cancel the context.
|
||||
func (c *Channel) Repeat(ctx context.Context, values ...any) <-chan any {
|
||||
dataStream := make(chan any)
|
||||
|
||||
go func() {
|
||||
defer close(dataStream)
|
||||
for {
|
||||
for _, v := range values {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case dataStream <- v:
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
return dataStream
|
||||
}
|
||||
|
||||
// RepeatFn return a chan, excutes fn repeatly, and put the result into retruned chan
|
||||
// until close the `done` channel
|
||||
func (c *Channel) RepeatFn(ctx context.Context, fn func() any) <-chan any {
|
||||
dataStream := make(chan any)
|
||||
|
||||
go func() {
|
||||
defer close(dataStream)
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case dataStream <- fn():
|
||||
}
|
||||
}
|
||||
}()
|
||||
return dataStream
|
||||
}
|
||||
|
||||
// Take return a chan whose values are tahken from another chan
|
||||
func (c *Channel) Take(ctx context.Context, valueStream <-chan any, number int) <-chan any {
|
||||
takeStream := make(chan any)
|
||||
|
||||
go func() {
|
||||
defer close(takeStream)
|
||||
|
||||
for i := 0; i < number; i++ {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case takeStream <- <-valueStream:
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return takeStream
|
||||
}
|
||||
|
||||
// FanIn merge multiple channels into one channel
|
||||
func (c *Channel) FanIn(ctx context.Context, channels ...<-chan any) <-chan any {
|
||||
out := make(chan any)
|
||||
|
||||
go func() {
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(len(channels))
|
||||
|
||||
for _, c := range channels {
|
||||
go func(c <-chan any) {
|
||||
defer wg.Done()
|
||||
for v := range c {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case out <- v:
|
||||
}
|
||||
}
|
||||
}(c)
|
||||
}
|
||||
wg.Wait()
|
||||
close(out)
|
||||
}()
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// Tee split one chanel into two channels
|
||||
func (c *Channel) Tee(ctx context.Context, in <-chan any) (<-chan any, <-chan any) {
|
||||
out1 := make(chan any)
|
||||
out2 := make(chan any)
|
||||
|
||||
go func() {
|
||||
defer close(out1)
|
||||
defer close(out2)
|
||||
|
||||
for val := range c.OrDone(ctx, in) {
|
||||
var out1, out2 = out1, out2
|
||||
for i := 0; i < 2; i++ {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
case out1 <- val:
|
||||
out1 = nil
|
||||
case out2 <- val:
|
||||
out2 = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return out1, out2
|
||||
}
|
||||
|
||||
// Bridge link multiply channels into one channel
|
||||
func (c *Channel) Bridge(ctx context.Context, chanStream <-chan <-chan any) <-chan any {
|
||||
valStream := make(chan any)
|
||||
|
||||
go func() {
|
||||
defer close(valStream)
|
||||
|
||||
for {
|
||||
var stream <-chan any
|
||||
select {
|
||||
case maybeStream, ok := <-chanStream:
|
||||
if ok == false {
|
||||
return
|
||||
}
|
||||
stream = maybeStream
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
|
||||
for val := range c.OrDone(ctx, stream) {
|
||||
select {
|
||||
case valStream <- val:
|
||||
case <-ctx.Done():
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return valStream
|
||||
}
|
||||
|
||||
// Or read one or more channels into one channel, will close when any readin channel is closed
|
||||
func (c *Channel) Or(channels ...<-chan any) <-chan any {
|
||||
switch len(channels) {
|
||||
case 0:
|
||||
return nil
|
||||
case 1:
|
||||
return channels[0]
|
||||
}
|
||||
|
||||
orDone := make(chan any)
|
||||
|
||||
go func() {
|
||||
defer close(orDone)
|
||||
|
||||
switch len(channels) {
|
||||
case 2:
|
||||
select {
|
||||
case <-channels[0]:
|
||||
case <-channels[1]:
|
||||
}
|
||||
default:
|
||||
m := len(channels) / 2
|
||||
select {
|
||||
case <-c.Or(channels[:m]...):
|
||||
case <-c.Or(channels[m:]...):
|
||||
}
|
||||
// select {
|
||||
// case <-channels[0]:
|
||||
// case <-channels[1]:
|
||||
// case <-channels[2]:
|
||||
// case <-c.Or(append(channels[3:], orDone)...):
|
||||
// }
|
||||
}
|
||||
}()
|
||||
|
||||
return orDone
|
||||
}
|
||||
|
||||
// OrDone read a channel into another channel, will close until cancel context.
|
||||
func (c *Channel) OrDone(ctx context.Context, channel <-chan any) <-chan any {
|
||||
valStream := make(chan any)
|
||||
|
||||
go func() {
|
||||
defer close(valStream)
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case v, ok := <-channel:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
select {
|
||||
case valStream <- v:
|
||||
case <-ctx.Done():
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}()
|
||||
|
||||
return valStream
|
||||
}
|
||||
206
concurrency/channel_test.go
Normal file
206
concurrency/channel_test.go
Normal file
@@ -0,0 +1,206 @@
|
||||
package concurrency
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestGenerate(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestGenerate")
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := NewChannel()
|
||||
intStream := c.Generate(ctx, 1, 2, 3)
|
||||
|
||||
// for v := range intStream {
|
||||
// t.Log(v) //1, 2, 3
|
||||
// }
|
||||
assert.Equal(1, <-intStream)
|
||||
assert.Equal(2, <-intStream)
|
||||
assert.Equal(3, <-intStream)
|
||||
}
|
||||
|
||||
func TestRepeat(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestRepeat")
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := NewChannel()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 5)
|
||||
|
||||
// for v := range intStream {
|
||||
// t.Log(v) //1, 2, 1, 2, 1
|
||||
// }
|
||||
assert.Equal(1, <-intStream)
|
||||
assert.Equal(2, <-intStream)
|
||||
assert.Equal(1, <-intStream)
|
||||
assert.Equal(2, <-intStream)
|
||||
assert.Equal(1, <-intStream)
|
||||
}
|
||||
|
||||
func TestRepeatFn(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestRepeatFn")
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
fn := func() any {
|
||||
s := "a"
|
||||
return s
|
||||
}
|
||||
c := NewChannel()
|
||||
dataStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3)
|
||||
|
||||
// for v := range dataStream {
|
||||
// t.Log(v) //a, a, a
|
||||
// }
|
||||
|
||||
assert.Equal("a", <-dataStream)
|
||||
assert.Equal("a", <-dataStream)
|
||||
assert.Equal("a", <-dataStream)
|
||||
}
|
||||
|
||||
func TestTake(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestTake")
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
numbers := make(chan any, 5)
|
||||
numbers <- 1
|
||||
numbers <- 2
|
||||
numbers <- 3
|
||||
numbers <- 4
|
||||
numbers <- 5
|
||||
defer close(numbers)
|
||||
|
||||
c := NewChannel()
|
||||
intStream := c.Take(ctx, numbers, 3)
|
||||
|
||||
assert.Equal(1, <-intStream)
|
||||
assert.Equal(2, <-intStream)
|
||||
assert.Equal(3, <-intStream)
|
||||
}
|
||||
|
||||
func TestFanIn(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestFanIn")
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := NewChannel()
|
||||
channels := make([]<-chan any, 3)
|
||||
|
||||
for i := 0; i < 3; i++ {
|
||||
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 3)
|
||||
}
|
||||
|
||||
mergedChannel := c.FanIn(ctx, channels...)
|
||||
|
||||
for val := range mergedChannel {
|
||||
t.Logf("\t%d\n", val)
|
||||
}
|
||||
|
||||
assert.Equal(1, 1)
|
||||
}
|
||||
|
||||
func TestOr(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestOr")
|
||||
|
||||
sig := func(after time.Duration) <-chan any {
|
||||
c := make(chan interface{})
|
||||
go func() {
|
||||
defer close(c)
|
||||
time.Sleep(after)
|
||||
}()
|
||||
return c
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
|
||||
c := NewChannel()
|
||||
<-c.Or(
|
||||
sig(1*time.Second),
|
||||
sig(2*time.Second),
|
||||
sig(3*time.Second),
|
||||
sig(4*time.Second),
|
||||
sig(5*time.Second),
|
||||
)
|
||||
|
||||
t.Logf("done after %v", time.Since(start))
|
||||
|
||||
assert.Equal(1, 1)
|
||||
}
|
||||
|
||||
func TestOrDone(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestOrDone")
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := NewChannel()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1), 3)
|
||||
|
||||
var res any
|
||||
for val := range c.OrDone(ctx, intStream) {
|
||||
t.Logf("%v", val)
|
||||
res = val
|
||||
}
|
||||
|
||||
assert.Equal(1, res)
|
||||
}
|
||||
|
||||
func TestTee(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestTee")
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := NewChannel()
|
||||
inStream := c.Take(ctx, c.Repeat(ctx, 1), 4)
|
||||
|
||||
out1, out2 := c.Tee(ctx, inStream)
|
||||
for val := range out1 {
|
||||
val1 := val
|
||||
val2 := <-out2
|
||||
// t.Log("val1 is", val1)
|
||||
// t.Log("val2 is", val2)
|
||||
assert.Equal(1, val1)
|
||||
assert.Equal(1, val2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBridge(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestBridge")
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := NewChannel()
|
||||
genVals := func() <-chan <-chan any {
|
||||
chanStream := make(chan (<-chan any))
|
||||
go func() {
|
||||
defer close(chanStream)
|
||||
for i := 0; i < 10; i++ {
|
||||
stream := make(chan any, 1)
|
||||
stream <- i
|
||||
close(stream)
|
||||
chanStream <- stream
|
||||
}
|
||||
}()
|
||||
return chanStream
|
||||
}
|
||||
|
||||
index := 0
|
||||
for val := range c.Bridge(ctx, genVals()) {
|
||||
// t.Logf("%v ", val) //0 1 2 3 4 5 6 7 8 9
|
||||
assert.Equal(index, val)
|
||||
index++
|
||||
}
|
||||
}
|
||||
@@ -234,7 +234,7 @@ func (link *DoublyLink[T]) IsEmpty() bool {
|
||||
return link.length == 0
|
||||
}
|
||||
|
||||
// Clear checks if link is empty or not
|
||||
// Clear all nodes in doubly linklist
|
||||
func (link *DoublyLink[T]) Clear() {
|
||||
link.Head = nil
|
||||
link.length = 0
|
||||
|
||||
@@ -227,7 +227,7 @@ func (link *SinglyLink[T]) IsEmpty() bool {
|
||||
return link.length == 0
|
||||
}
|
||||
|
||||
// Clear checks if link is empty or not
|
||||
// Clear all the node in singly linklist
|
||||
func (link *SinglyLink[T]) Clear() {
|
||||
link.Head = nil
|
||||
link.length = 0
|
||||
|
||||
@@ -132,8 +132,8 @@ func (l *List[T]) UpdateAt(index int, value T) {
|
||||
l.data = append(data[:index], append([]T{value}, data[index+1:]...)...)
|
||||
}
|
||||
|
||||
// Equtal compare list to other list, use reflect.DeepEqual
|
||||
func (l *List[T]) Equtal(other *List[T]) bool {
|
||||
// Equal compare list to other list, use reflect.DeepEqual
|
||||
func (l *List[T]) Equal(other *List[T]) bool {
|
||||
if len(l.data) != len(other.data) {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -155,15 +155,15 @@ func TestUpdateAt(t *testing.T) {
|
||||
assert.Equal([]int{5, 2, 3, 1}, list.Data())
|
||||
}
|
||||
|
||||
func TestEqutal(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestEqutal")
|
||||
func TestEqual(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestEqual")
|
||||
|
||||
list1 := NewList([]int{1, 2, 3, 4})
|
||||
list2 := NewList([]int{1, 2, 3, 4})
|
||||
list3 := NewList([]int{1, 2, 3})
|
||||
|
||||
assert.Equal(true, list1.Equtal(list2))
|
||||
assert.Equal(false, list1.Equtal(list3))
|
||||
assert.Equal(true, list1.Equal(list2))
|
||||
assert.Equal(false, list1.Equal(list3))
|
||||
}
|
||||
|
||||
func TestIsEmpty(t *testing.T) {
|
||||
@@ -192,7 +192,7 @@ func TestClone(t *testing.T) {
|
||||
list1 := NewList([]int{1, 2, 3, 4})
|
||||
list2 := list1.Clone()
|
||||
|
||||
assert.Equal(true, list1.Equtal(list2))
|
||||
assert.Equal(true, list1.Equal(list2))
|
||||
}
|
||||
|
||||
func TestMerge(t *testing.T) {
|
||||
@@ -203,7 +203,7 @@ func TestMerge(t *testing.T) {
|
||||
expected := NewList([]int{1, 2, 3, 4, 4, 5, 6})
|
||||
|
||||
list3 := list1.Merge(list2)
|
||||
assert.Equal(true, expected.Equtal(list3))
|
||||
assert.Equal(true, expected.Equal(list3))
|
||||
}
|
||||
|
||||
func TestSize(t *testing.T) {
|
||||
@@ -224,7 +224,7 @@ func TestSwap(t *testing.T) {
|
||||
|
||||
list.Swap(0, 3)
|
||||
|
||||
assert.Equal(true, expected.Equtal(list))
|
||||
assert.Equal(true, expected.Equal(list))
|
||||
}
|
||||
|
||||
func TestReverse(t *testing.T) {
|
||||
@@ -235,7 +235,7 @@ func TestReverse(t *testing.T) {
|
||||
|
||||
list.Reverse()
|
||||
|
||||
assert.Equal(true, expected.Equtal(list))
|
||||
assert.Equal(true, expected.Equal(list))
|
||||
}
|
||||
|
||||
func TestUnique(t *testing.T) {
|
||||
@@ -246,7 +246,7 @@ func TestUnique(t *testing.T) {
|
||||
|
||||
list.Unique()
|
||||
|
||||
assert.Equal(true, expected.Equtal(list))
|
||||
assert.Equal(true, expected.Equal(list))
|
||||
}
|
||||
|
||||
func TestUnion(t *testing.T) {
|
||||
@@ -257,7 +257,7 @@ func TestUnion(t *testing.T) {
|
||||
expected := NewList([]int{1, 2, 3, 4, 5, 6})
|
||||
|
||||
list3 := list1.Union(list2)
|
||||
assert.Equal(true, expected.Equtal(list3))
|
||||
assert.Equal(true, expected.Equal(list3))
|
||||
}
|
||||
|
||||
func TestIntersection(t *testing.T) {
|
||||
@@ -268,5 +268,5 @@ func TestIntersection(t *testing.T) {
|
||||
expected := NewList([]int{4})
|
||||
|
||||
list3 := list1.Intersection(list2)
|
||||
assert.Equal(true, expected.Equtal(list3))
|
||||
assert.Equal(true, expected.Equal(list3))
|
||||
}
|
||||
|
||||
@@ -40,12 +40,12 @@ func NewQueueNode[T any](value T) *QueueNode[T] {
|
||||
|
||||
// TreeNode is node of tree
|
||||
type TreeNode[T any] struct {
|
||||
Data T
|
||||
Value T
|
||||
Left *TreeNode[T]
|
||||
Right *TreeNode[T]
|
||||
}
|
||||
|
||||
// NewTreeNode return a TreeNode pointer
|
||||
func NewTreeNode[T any](data T) *TreeNode[T] {
|
||||
return &TreeNode[T]{data, nil, nil}
|
||||
func NewTreeNode[T any](val T) *TreeNode[T] {
|
||||
return &TreeNode[T]{val, nil, nil}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ func NewArrayQueue[T any](capacity int) *ArrayQueue[T] {
|
||||
}
|
||||
}
|
||||
|
||||
// Data return queue data
|
||||
// Data return slice of queue data
|
||||
func (q *ArrayQueue[T]) Data() []T {
|
||||
items := []T{}
|
||||
for i := q.head; i < q.tail; i++ {
|
||||
@@ -43,6 +43,11 @@ func (q *ArrayQueue[T]) IsEmpty() bool {
|
||||
return q.size == 0
|
||||
}
|
||||
|
||||
// IsFull checks if queue is full or not
|
||||
func (q *ArrayQueue[T]) IsFull() bool {
|
||||
return q.size == q.capacity
|
||||
}
|
||||
|
||||
// Front return front value of queue
|
||||
func (q *ArrayQueue[T]) Front() T {
|
||||
return q.items[0]
|
||||
|
||||
@@ -100,3 +100,14 @@ func TestArrayQueue_Clear(t *testing.T) {
|
||||
assert.Equal(true, queue.IsEmpty())
|
||||
assert.Equal(0, queue.Size())
|
||||
}
|
||||
|
||||
func TestArrayQueue_IsFull(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestArrayQueue_IsFull")
|
||||
|
||||
queue := NewArrayQueue[int](3)
|
||||
queue.Enqueue(1)
|
||||
queue.Enqueue(2)
|
||||
queue.Enqueue(3)
|
||||
|
||||
assert.Equal(true, queue.IsFull())
|
||||
}
|
||||
|
||||
@@ -7,21 +7,21 @@ import (
|
||||
)
|
||||
|
||||
// CircularQueue implements circular queue with slice,
|
||||
// last index of CircularQueue don't contain value, so acturl capacity is size - 1
|
||||
// last index of CircularQueue don't contain value, so acturl capacity is capacity - 1
|
||||
type CircularQueue[T any] struct {
|
||||
data []T
|
||||
front int
|
||||
rear int
|
||||
size int
|
||||
capacity int
|
||||
}
|
||||
|
||||
// NewCircularQueue return a empty CircularQueue pointer
|
||||
func NewCircularQueue[T any](size int) *CircularQueue[T] {
|
||||
data := make([]T, size)
|
||||
return &CircularQueue[T]{data: data, front: 0, rear: 0, size: size}
|
||||
func NewCircularQueue[T any](capacity int) *CircularQueue[T] {
|
||||
data := make([]T, capacity)
|
||||
return &CircularQueue[T]{data: data, front: 0, rear: 0, capacity: capacity}
|
||||
}
|
||||
|
||||
// Data return queue data
|
||||
// Data return slice of queue data
|
||||
func (q *CircularQueue[T]) Data() []T {
|
||||
data := []T{}
|
||||
|
||||
@@ -37,12 +37,12 @@ func (q *CircularQueue[T]) Data() []T {
|
||||
return data
|
||||
}
|
||||
|
||||
// Length return current data length of queue
|
||||
func (q *CircularQueue[T]) Length() int {
|
||||
if q.size == 0 {
|
||||
// Size return number of elements in circular queue
|
||||
func (q *CircularQueue[T]) Size() int {
|
||||
if q.capacity == 0 {
|
||||
return 0
|
||||
}
|
||||
return (q.rear - q.front + q.size) % q.size
|
||||
return (q.rear - q.front + q.capacity) % q.capacity
|
||||
}
|
||||
|
||||
// IsEmpty checks if queue is empty or not
|
||||
@@ -52,7 +52,7 @@ func (q *CircularQueue[T]) IsEmpty() bool {
|
||||
|
||||
// IsFull checks if queue is full or not
|
||||
func (q *CircularQueue[T]) IsFull() bool {
|
||||
return (q.rear+1)%q.size == q.front
|
||||
return (q.rear+1)%q.capacity == q.front
|
||||
}
|
||||
|
||||
// Front return front value of queue
|
||||
@@ -65,23 +65,23 @@ func (q *CircularQueue[T]) Back() T {
|
||||
if q.rear-1 >= 0 {
|
||||
return q.data[q.rear-1]
|
||||
}
|
||||
return q.data[q.size-1]
|
||||
return q.data[q.capacity-1]
|
||||
}
|
||||
|
||||
// EnQueue put element into queue
|
||||
func (q *CircularQueue[T]) EnQueue(value T) error {
|
||||
// Enqueue put element into queue
|
||||
func (q *CircularQueue[T]) Enqueue(value T) error {
|
||||
if q.IsFull() {
|
||||
return errors.New("queue is full!")
|
||||
}
|
||||
|
||||
q.data[q.rear] = value
|
||||
q.rear = (q.rear + 1) % q.size
|
||||
q.rear = (q.rear + 1) % q.capacity
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeQueue remove head element of queue and return it, if queue is empty, return nil and error
|
||||
func (q *CircularQueue[T]) DeQueue() (*T, error) {
|
||||
// Dequeue remove head element of queue and return it, if queue is empty, return nil and error
|
||||
func (q *CircularQueue[T]) Dequeue() (*T, error) {
|
||||
if q.IsEmpty() {
|
||||
return nil, errors.New("queue is empty")
|
||||
}
|
||||
@@ -89,7 +89,7 @@ func (q *CircularQueue[T]) DeQueue() (*T, error) {
|
||||
headItem := q.data[q.front]
|
||||
var t T
|
||||
q.data[q.front] = t
|
||||
q.front = (q.front + 1) % q.size
|
||||
q.front = (q.front + 1) % q.capacity
|
||||
|
||||
return &headItem, nil
|
||||
}
|
||||
@@ -99,7 +99,7 @@ func (q *CircularQueue[T]) Clear() {
|
||||
q.data = []T{}
|
||||
q.front = 0
|
||||
q.rear = 0
|
||||
q.size = 0
|
||||
q.capacity = 0
|
||||
}
|
||||
|
||||
// Contain checks if the value is in queue or not
|
||||
|
||||
@@ -6,47 +6,47 @@ import (
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestCircularQueue_EnQueue(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestCircularQueue_EnQueue")
|
||||
func TestCircularQueue_Enqueue(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestCircularQueue_Enqueue")
|
||||
|
||||
queue := NewCircularQueue[int](6)
|
||||
queue.EnQueue(1)
|
||||
queue.EnQueue(2)
|
||||
queue.EnQueue(3)
|
||||
queue.EnQueue(4)
|
||||
queue.EnQueue(5)
|
||||
queue.Enqueue(1)
|
||||
queue.Enqueue(2)
|
||||
queue.Enqueue(3)
|
||||
queue.Enqueue(4)
|
||||
queue.Enqueue(5)
|
||||
|
||||
queue.Print()
|
||||
// assert.Equal([]int{1, 2, 3, 4, 5}, queue.Data())
|
||||
assert.Equal(5, queue.Length())
|
||||
assert.Equal([]int{1, 2, 3, 4, 5}, queue.Data())
|
||||
assert.Equal(5, queue.Size())
|
||||
|
||||
err := queue.EnQueue(6)
|
||||
err := queue.Enqueue(6)
|
||||
assert.IsNotNil(err)
|
||||
}
|
||||
|
||||
func TestCircularQueue_DeQueue(t *testing.T) {
|
||||
func TestCircularQueue_Dequeue(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestCircularQueue_DeQueue")
|
||||
|
||||
queue := NewCircularQueue[int](6)
|
||||
assert.Equal(true, queue.IsEmpty())
|
||||
|
||||
queue.EnQueue(1)
|
||||
queue.EnQueue(2)
|
||||
queue.EnQueue(3)
|
||||
queue.EnQueue(4)
|
||||
queue.EnQueue(5)
|
||||
queue.Enqueue(1)
|
||||
queue.Enqueue(2)
|
||||
queue.Enqueue(3)
|
||||
queue.Enqueue(4)
|
||||
queue.Enqueue(5)
|
||||
|
||||
val, err := queue.DeQueue()
|
||||
val, err := queue.Dequeue()
|
||||
assert.IsNil(err)
|
||||
|
||||
assert.Equal(1, *val)
|
||||
assert.Equal(false, queue.IsFull())
|
||||
|
||||
val, _ = queue.DeQueue()
|
||||
val, _ = queue.Dequeue()
|
||||
queue.Print()
|
||||
assert.Equal(2, *val)
|
||||
|
||||
queue.EnQueue(6)
|
||||
queue.Enqueue(6)
|
||||
queue.Print()
|
||||
assert.Equal(false, queue.IsFull())
|
||||
}
|
||||
@@ -55,24 +55,24 @@ func TestCircularQueue_Front(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestCircularQueue_Front")
|
||||
|
||||
queue := NewCircularQueue[int](6)
|
||||
queue.EnQueue(1)
|
||||
queue.EnQueue(2)
|
||||
queue.EnQueue(3)
|
||||
queue.EnQueue(4)
|
||||
queue.EnQueue(5)
|
||||
queue.Enqueue(1)
|
||||
queue.Enqueue(2)
|
||||
queue.Enqueue(3)
|
||||
queue.Enqueue(4)
|
||||
queue.Enqueue(5)
|
||||
|
||||
queue.Print()
|
||||
|
||||
queue.DeQueue()
|
||||
queue.DeQueue()
|
||||
queue.EnQueue(6)
|
||||
queue.EnQueue(7)
|
||||
queue.Dequeue()
|
||||
queue.Dequeue()
|
||||
queue.Enqueue(6)
|
||||
queue.Enqueue(7)
|
||||
|
||||
queue.Print()
|
||||
|
||||
val := queue.Front()
|
||||
assert.Equal(3, val)
|
||||
assert.Equal(5, queue.Length())
|
||||
assert.Equal(5, queue.Size())
|
||||
}
|
||||
|
||||
func TestCircularQueue_Back(t *testing.T) {
|
||||
@@ -81,19 +81,19 @@ func TestCircularQueue_Back(t *testing.T) {
|
||||
queue := NewCircularQueue[int](6)
|
||||
assert.Equal(true, queue.IsEmpty())
|
||||
|
||||
queue.EnQueue(1)
|
||||
queue.EnQueue(2)
|
||||
queue.EnQueue(3)
|
||||
queue.EnQueue(4)
|
||||
queue.EnQueue(5)
|
||||
queue.Enqueue(1)
|
||||
queue.Enqueue(2)
|
||||
queue.Enqueue(3)
|
||||
queue.Enqueue(4)
|
||||
queue.Enqueue(5)
|
||||
|
||||
queue.Print()
|
||||
assert.Equal(5, queue.Back())
|
||||
|
||||
queue.DeQueue()
|
||||
queue.DeQueue()
|
||||
queue.EnQueue(6)
|
||||
queue.EnQueue(7)
|
||||
queue.Dequeue()
|
||||
queue.Dequeue()
|
||||
queue.Enqueue(6)
|
||||
queue.Enqueue(7)
|
||||
|
||||
queue.Print()
|
||||
assert.Equal(7, queue.Back())
|
||||
@@ -103,7 +103,7 @@ func TestCircularQueue_Contain(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestCircularQueue_Contain")
|
||||
|
||||
queue := NewCircularQueue[int](2)
|
||||
queue.EnQueue(1)
|
||||
queue.Enqueue(1)
|
||||
assert.Equal(true, queue.Contain(1))
|
||||
assert.Equal(false, queue.Contain(2))
|
||||
}
|
||||
@@ -113,34 +113,34 @@ func TestCircularQueue_Clear(t *testing.T) {
|
||||
|
||||
queue := NewCircularQueue[int](3)
|
||||
assert.Equal(true, queue.IsEmpty())
|
||||
assert.Equal(0, queue.Length())
|
||||
assert.Equal(0, queue.Size())
|
||||
|
||||
queue.EnQueue(1)
|
||||
queue.Enqueue(1)
|
||||
assert.Equal(false, queue.IsEmpty())
|
||||
assert.Equal(1, queue.Length())
|
||||
assert.Equal(1, queue.Size())
|
||||
|
||||
queue.Clear()
|
||||
assert.Equal(true, queue.IsEmpty())
|
||||
assert.Equal(0, queue.Length())
|
||||
assert.Equal(0, queue.Size())
|
||||
}
|
||||
|
||||
func TestCircularQueue_Data(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestCircularQueue_Data")
|
||||
|
||||
queue := NewCircularQueue[int](6)
|
||||
queue.EnQueue(1)
|
||||
queue.EnQueue(2)
|
||||
queue.EnQueue(3)
|
||||
queue.EnQueue(4)
|
||||
queue.EnQueue(5)
|
||||
queue.Enqueue(1)
|
||||
queue.Enqueue(2)
|
||||
queue.Enqueue(3)
|
||||
queue.Enqueue(4)
|
||||
queue.Enqueue(5)
|
||||
|
||||
queue.Print()
|
||||
assert.Equal([]int{1, 2, 3, 4, 5}, queue.Data())
|
||||
|
||||
queue.DeQueue()
|
||||
queue.DeQueue()
|
||||
queue.EnQueue(6)
|
||||
queue.EnQueue(7)
|
||||
queue.Dequeue()
|
||||
queue.Dequeue()
|
||||
queue.Enqueue(6)
|
||||
queue.Enqueue(7)
|
||||
|
||||
queue.Print()
|
||||
assert.Equal([]int{3, 4, 5, 6, 7}, queue.Data())
|
||||
|
||||
@@ -3,6 +3,7 @@ package datastructure
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/duke-git/lancet/v2/datastructure"
|
||||
)
|
||||
@@ -19,7 +20,7 @@ func NewLinkedQueue[T any]() *LinkedQueue[T] {
|
||||
return &LinkedQueue[T]{head: nil, tail: nil, length: 0}
|
||||
}
|
||||
|
||||
// Data return queue data
|
||||
// Data return slice of queue data
|
||||
func (q *LinkedQueue[T]) Data() []T {
|
||||
res := []T{}
|
||||
current := q.head
|
||||
@@ -41,8 +42,9 @@ func (q *LinkedQueue[T]) IsEmpty() bool {
|
||||
return q.length == 0
|
||||
}
|
||||
|
||||
// EnQueue add element into queue
|
||||
func (q *LinkedQueue[T]) EnQueue(value T) {
|
||||
|
||||
// Enqueue put element into queue
|
||||
func (q *LinkedQueue[T]) Enqueue(value T) {
|
||||
newNode := datastructure.NewQueueNode(value)
|
||||
|
||||
if q.IsEmpty() {
|
||||
@@ -55,8 +57,8 @@ func (q *LinkedQueue[T]) EnQueue(value T) {
|
||||
q.length++
|
||||
}
|
||||
|
||||
// DeQueue delete head element of queue then return it, if queue is empty, return nil and error
|
||||
func (q *LinkedQueue[T]) DeQueue() (*T, error) {
|
||||
// Dequeue delete head element of queue then return it, if queue is empty, return nil and error
|
||||
func (q *LinkedQueue[T]) Dequeue() (*T, error) {
|
||||
if q.IsEmpty() {
|
||||
return nil, errors.New("queue is empty")
|
||||
}
|
||||
@@ -102,3 +104,15 @@ func (q *LinkedQueue[T]) Print() {
|
||||
info += " ]"
|
||||
fmt.Println(info)
|
||||
}
|
||||
|
||||
// Contain checks if the value is in queue or not
|
||||
func (q *LinkedQueue[T]) Contain(value T) bool {
|
||||
current := q.head
|
||||
for current != nil {
|
||||
if reflect.DeepEqual(current.Value, value) {
|
||||
return true
|
||||
}
|
||||
current = current.Next
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -6,13 +6,13 @@ import (
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestLinkedQueue_EnQueue(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestLinkedQueue_EnQueue")
|
||||
func TestLinkedQueue_Enqueue(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestLinkedQueue_Enqueue")
|
||||
|
||||
queue := NewLinkedQueue[int]()
|
||||
queue.EnQueue(1)
|
||||
queue.EnQueue(2)
|
||||
queue.EnQueue(3)
|
||||
queue.Enqueue(1)
|
||||
queue.Enqueue(2)
|
||||
queue.Enqueue(3)
|
||||
|
||||
queue.Print()
|
||||
|
||||
@@ -20,15 +20,15 @@ func TestLinkedQueue_EnQueue(t *testing.T) {
|
||||
assert.Equal(3, queue.Size())
|
||||
}
|
||||
|
||||
func TestLinkedQueue_DeQueue(t *testing.T) {
|
||||
func TestLinkedQueue_Dequeue(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestLinkedQueue_DeQueue")
|
||||
|
||||
queue := NewLinkedQueue[int]()
|
||||
queue.EnQueue(1)
|
||||
queue.EnQueue(2)
|
||||
queue.EnQueue(3)
|
||||
queue.Enqueue(1)
|
||||
queue.Enqueue(2)
|
||||
queue.Enqueue(3)
|
||||
|
||||
val, _ := queue.DeQueue()
|
||||
val, _ := queue.Dequeue()
|
||||
|
||||
queue.Print()
|
||||
|
||||
@@ -43,9 +43,9 @@ func TestLinkedQueue_Front(t *testing.T) {
|
||||
_, err := queue.Front()
|
||||
assert.IsNotNil(err)
|
||||
|
||||
queue.EnQueue(1)
|
||||
queue.EnQueue(2)
|
||||
queue.EnQueue(3)
|
||||
queue.Enqueue(1)
|
||||
queue.Enqueue(2)
|
||||
queue.Enqueue(3)
|
||||
|
||||
val, err := queue.Front()
|
||||
assert.Equal(1, *val)
|
||||
@@ -59,9 +59,9 @@ func TestLinkedQueue_Back(t *testing.T) {
|
||||
_, err := queue.Back()
|
||||
assert.IsNotNil(err)
|
||||
|
||||
queue.EnQueue(1)
|
||||
queue.EnQueue(2)
|
||||
queue.EnQueue(3)
|
||||
queue.Enqueue(1)
|
||||
queue.Enqueue(2)
|
||||
queue.Enqueue(3)
|
||||
|
||||
val, err := queue.Back()
|
||||
assert.Equal(3, *val)
|
||||
@@ -74,11 +74,24 @@ func TestLinkedQueue_Clear(t *testing.T) {
|
||||
queue := NewLinkedQueue[int]()
|
||||
assert.Equal(true, queue.IsEmpty())
|
||||
|
||||
queue.EnQueue(1)
|
||||
queue.EnQueue(2)
|
||||
queue.EnQueue(3)
|
||||
queue.Enqueue(1)
|
||||
queue.Enqueue(2)
|
||||
queue.Enqueue(3)
|
||||
assert.Equal(false, queue.IsEmpty())
|
||||
|
||||
queue.Clear()
|
||||
assert.Equal(true, queue.IsEmpty())
|
||||
}
|
||||
|
||||
func TestLinkedQueue_Contain(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestLinkedQueue_Contain")
|
||||
|
||||
queue := NewLinkedQueue[int]()
|
||||
|
||||
queue.Enqueue(1)
|
||||
queue.Enqueue(2)
|
||||
queue.Enqueue(3)
|
||||
|
||||
assert.Equal(true, queue.Contain(1))
|
||||
assert.Equal(false, queue.Contain(4))
|
||||
}
|
||||
|
||||
113
datastructure/queue/priorityqueue.go
Normal file
113
datastructure/queue/priorityqueue.go
Normal file
@@ -0,0 +1,113 @@
|
||||
package datastructure
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/duke-git/lancet/v2/lancetconstraints"
|
||||
)
|
||||
|
||||
// PriorityQueue is a priority queue implemented by binary heap tree
|
||||
// type T should implements Compare function in lancetconstraints.Comparator interface.
|
||||
type PriorityQueue[T any] struct {
|
||||
items []T
|
||||
size int
|
||||
comparator lancetconstraints.Comparator
|
||||
}
|
||||
|
||||
// NewPriorityQueue return a pointer of PriorityQueue
|
||||
// param `comparator` is used to compare values in the queue
|
||||
func NewPriorityQueue[T any](capacity int, comparator lancetconstraints.Comparator) *PriorityQueue[T] {
|
||||
return &PriorityQueue[T]{
|
||||
items: make([]T, capacity+1),
|
||||
size: 0,
|
||||
comparator: comparator,
|
||||
}
|
||||
}
|
||||
|
||||
// IsEmpty checks if the queue is empty or not
|
||||
func (q *PriorityQueue[T]) IsEmpty() bool {
|
||||
return q.size == 0
|
||||
}
|
||||
|
||||
// Size get number of items in the queue
|
||||
func (q *PriorityQueue[T]) Size() int {
|
||||
return q.size
|
||||
}
|
||||
|
||||
// IsFull checks if the queue capacity is full or not
|
||||
func (q *PriorityQueue[T]) IsFull() bool {
|
||||
return q.size == len(q.items)-1
|
||||
}
|
||||
|
||||
// Data return a slice of queue data
|
||||
func (q *PriorityQueue[T]) Data() []T {
|
||||
data := make([]T, q.size)
|
||||
for i := 1; i < q.size+1; i++ {
|
||||
data[i-1] = q.items[i]
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
// Enqueue insert value into queue
|
||||
func (q *PriorityQueue[T]) Enqueue(val T) error {
|
||||
if q.IsFull() {
|
||||
return errors.New("queue is already full.")
|
||||
}
|
||||
q.size++
|
||||
q.items[q.size] = val
|
||||
q.swim(q.size)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Dequeue delete and return max value in queue
|
||||
func (q *PriorityQueue[T]) Dequeue() (T, bool) {
|
||||
var val T
|
||||
if q.IsEmpty() {
|
||||
return val, false
|
||||
}
|
||||
|
||||
max := q.items[1]
|
||||
|
||||
q.swap(1, q.size)
|
||||
q.size--
|
||||
q.sink(1)
|
||||
|
||||
//set zero value for rest values of the queue
|
||||
q.items[q.size+1] = val
|
||||
|
||||
return max, true
|
||||
}
|
||||
|
||||
// swim when child's key is larger than parent's key, exchange them.
|
||||
func (q *PriorityQueue[T]) swim(index int) {
|
||||
for index > 1 && q.comparator.Compare(q.items[index/2], q.items[index]) < 0 {
|
||||
q.swap(index, index/2)
|
||||
index = index / 2
|
||||
}
|
||||
}
|
||||
|
||||
// sink when parent's key smaller than child's key, exchange parent's key with larger child's key.
|
||||
func (q *PriorityQueue[T]) sink(index int) {
|
||||
|
||||
for 2*index <= q.size {
|
||||
j := 2 * index
|
||||
|
||||
// get larger child node index
|
||||
if j < q.size && q.comparator.Compare(q.items[j], q.items[j+1]) < 0 {
|
||||
j++
|
||||
}
|
||||
// if parent larger than child, stop
|
||||
if !(q.comparator.Compare(q.items[index], q.items[j]) < 0) {
|
||||
break
|
||||
}
|
||||
|
||||
q.swap(index, j)
|
||||
index = j
|
||||
}
|
||||
}
|
||||
|
||||
// swap the two values at index i and j
|
||||
func (q *PriorityQueue[T]) swap(i, j int) {
|
||||
q.items[i], q.items[j] = q.items[j], q.items[i]
|
||||
}
|
||||
64
datastructure/queue/priorityqueue_test.go
Normal file
64
datastructure/queue/priorityqueue_test.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package datastructure
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
func TestPriorityQueue_Enqueue(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestPriorityQueue_Enqueue")
|
||||
|
||||
comparator := &intComparator{}
|
||||
pq := NewPriorityQueue[int](10, comparator)
|
||||
|
||||
assert.Equal(true, pq.IsEmpty())
|
||||
assert.Equal(false, pq.IsFull())
|
||||
|
||||
for i := 1; i < 11; i++ {
|
||||
pq.Enqueue(i)
|
||||
}
|
||||
|
||||
assert.Equal(true, pq.IsFull())
|
||||
|
||||
queueData := pq.Data()
|
||||
assert.Equal([]int{10, 9, 6, 7, 8, 2, 5, 1, 4, 3}, queueData)
|
||||
|
||||
}
|
||||
|
||||
func TestPriorityQueue_Dequeue(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestPriorityQueue_Dequeue")
|
||||
|
||||
comparator := &intComparator{}
|
||||
pq := NewPriorityQueue[int](10, comparator)
|
||||
|
||||
_, ok := pq.Dequeue()
|
||||
assert.Equal(false, ok)
|
||||
|
||||
for i := 1; i < 11; i++ {
|
||||
pq.Enqueue(i)
|
||||
}
|
||||
|
||||
assert.Equal(10, pq.Size())
|
||||
|
||||
val, ok := pq.Dequeue()
|
||||
assert.Equal(true, ok)
|
||||
assert.Equal(10, val)
|
||||
|
||||
assert.Equal([]int{9, 8, 6, 7, 3, 2, 5, 1, 4}, pq.Data())
|
||||
|
||||
assert.Equal(9, pq.Size())
|
||||
}
|
||||
@@ -23,7 +23,7 @@ func (s Set[T]) Contain(value T) bool {
|
||||
return ok
|
||||
}
|
||||
|
||||
// Contain checks if set contains other set
|
||||
// ContainAll checks if set contains other set
|
||||
func (s Set[T]) ContainAll(other Set[T]) bool {
|
||||
for k := range other {
|
||||
_, ok := s[k]
|
||||
|
||||
@@ -47,7 +47,7 @@ func (s *ArrayStack[T]) Pop() (*T, error) {
|
||||
return &topItem, nil
|
||||
}
|
||||
|
||||
// Peak return the top element of stack then return it
|
||||
// Peak return the top element of stack
|
||||
func (s *ArrayStack[T]) Peak() (*T, error) {
|
||||
if s.IsEmpty() {
|
||||
return nil, errors.New("stack is empty")
|
||||
|
||||
@@ -12,29 +12,31 @@ import (
|
||||
// In BSTree: leftNode < rootNode < rightNode
|
||||
// type T should implements Compare function in lancetconstraints.Comparator interface.
|
||||
type BSTree[T any] struct {
|
||||
root *datastructure.TreeNode[T]
|
||||
root *datastructure.TreeNode[T]
|
||||
comparator lancetconstraints.Comparator
|
||||
}
|
||||
|
||||
// NewBSTree create a BSTree pointer
|
||||
func NewBSTree[T any](rootData T) *BSTree[T] {
|
||||
// param `comparator` is used to compare values in the tree
|
||||
func NewBSTree[T any](rootData T, comparator lancetconstraints.Comparator) *BSTree[T] {
|
||||
root := datastructure.NewTreeNode(rootData)
|
||||
return &BSTree[T]{root}
|
||||
return &BSTree[T]{root, comparator}
|
||||
}
|
||||
|
||||
// InsertNode insert data into BSTree
|
||||
func (t *BSTree[T]) InsertNode(data T, comparator lancetconstraints.Comparator) {
|
||||
func (t *BSTree[T]) Insert(data T) {
|
||||
root := t.root
|
||||
newNode := datastructure.NewTreeNode(data)
|
||||
if root == nil {
|
||||
t.root = newNode
|
||||
} else {
|
||||
insertTreeNode(root, newNode, comparator)
|
||||
insertTreeNode(root, newNode, t.comparator)
|
||||
}
|
||||
}
|
||||
|
||||
// DeletetNode delete data into BSTree
|
||||
func (t *BSTree[T]) DeletetNode(data T, comparator lancetconstraints.Comparator) {
|
||||
deleteTreeNode(t.root, data, comparator)
|
||||
func (t *BSTree[T]) Delete(data T) {
|
||||
deleteTreeNode(t.root, data, t.comparator)
|
||||
}
|
||||
|
||||
// NodeLevel get node level in BSTree
|
||||
@@ -75,6 +77,29 @@ func (t *BSTree[T]) Depth() int {
|
||||
return calculateDepth(t.root, 0)
|
||||
}
|
||||
|
||||
// IsSubTree checks if the tree `t` has `subTree` or not
|
||||
func (t *BSTree[T]) HasSubTree(subTree *BSTree[T]) bool {
|
||||
return hasSubTree(t.root, subTree.root, t.comparator)
|
||||
}
|
||||
|
||||
func hasSubTree[T any](superTreeRoot, subTreeRoot *datastructure.TreeNode[T],
|
||||
comparator lancetconstraints.Comparator) bool {
|
||||
res := false
|
||||
|
||||
if superTreeRoot != nil && subTreeRoot != nil {
|
||||
if comparator.Compare(superTreeRoot.Value, subTreeRoot.Value) == 0 {
|
||||
res = isSubTree(superTreeRoot, subTreeRoot, comparator)
|
||||
}
|
||||
if !res {
|
||||
res = hasSubTree(superTreeRoot.Left, subTreeRoot, comparator)
|
||||
}
|
||||
if !res {
|
||||
res = hasSubTree(superTreeRoot.Right, subTreeRoot, comparator)
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// Print the bstree structure
|
||||
func (t *BSTree[T]) Print() {
|
||||
maxLevel := t.NodeLevel(t.root)
|
||||
|
||||
@@ -20,14 +20,13 @@ func (c *intComparator) Compare(v1, v2 any) int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func TestBSTree_InsertNode(t *testing.T) {
|
||||
bstree := NewBSTree(6)
|
||||
func TestBSTree_Insert(t *testing.T) {
|
||||
bstree := NewBSTree(6, &intComparator{})
|
||||
|
||||
comparator := &intComparator{}
|
||||
bstree.InsertNode(7, comparator)
|
||||
bstree.InsertNode(5, comparator)
|
||||
bstree.InsertNode(2, comparator)
|
||||
bstree.InsertNode(4, comparator)
|
||||
bstree.Insert(7)
|
||||
bstree.Insert(5)
|
||||
bstree.Insert(2)
|
||||
bstree.Insert(4)
|
||||
|
||||
bstree.Print()
|
||||
}
|
||||
@@ -35,13 +34,12 @@ func TestBSTree_InsertNode(t *testing.T) {
|
||||
func TestBSTree_PreOrderTraverse(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestBSTree_PreOrderTraverse")
|
||||
|
||||
bstree := NewBSTree(6)
|
||||
bstree := NewBSTree(6, &intComparator{})
|
||||
|
||||
comparator := &intComparator{}
|
||||
bstree.InsertNode(7, comparator)
|
||||
bstree.InsertNode(5, comparator)
|
||||
bstree.InsertNode(2, comparator)
|
||||
bstree.InsertNode(4, comparator)
|
||||
bstree.Insert(7)
|
||||
bstree.Insert(5)
|
||||
bstree.Insert(2)
|
||||
bstree.Insert(4)
|
||||
|
||||
acturl := bstree.PreOrderTraverse()
|
||||
t.Log(acturl)
|
||||
@@ -51,13 +49,12 @@ func TestBSTree_PreOrderTraverse(t *testing.T) {
|
||||
func TestBSTree_PostOrderTraverse(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestBSTree_PostOrderTraverse")
|
||||
|
||||
bstree := NewBSTree(6)
|
||||
bstree := NewBSTree(6, &intComparator{})
|
||||
|
||||
comparator := &intComparator{}
|
||||
bstree.InsertNode(7, comparator)
|
||||
bstree.InsertNode(5, comparator)
|
||||
bstree.InsertNode(2, comparator)
|
||||
bstree.InsertNode(4, comparator)
|
||||
bstree.Insert(7)
|
||||
bstree.Insert(5)
|
||||
bstree.Insert(2)
|
||||
bstree.Insert(4)
|
||||
|
||||
acturl := bstree.PostOrderTraverse()
|
||||
t.Log(acturl)
|
||||
@@ -67,13 +64,12 @@ func TestBSTree_PostOrderTraverse(t *testing.T) {
|
||||
func TestBSTree_InOrderTraverse(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestBSTree_InOrderTraverse")
|
||||
|
||||
bstree := NewBSTree(6)
|
||||
bstree := NewBSTree(6, &intComparator{})
|
||||
|
||||
comparator := &intComparator{}
|
||||
bstree.InsertNode(7, comparator)
|
||||
bstree.InsertNode(5, comparator)
|
||||
bstree.InsertNode(2, comparator)
|
||||
bstree.InsertNode(4, comparator)
|
||||
bstree.Insert(7)
|
||||
bstree.Insert(5)
|
||||
bstree.Insert(2)
|
||||
bstree.Insert(4)
|
||||
|
||||
acturl := bstree.InOrderTraverse()
|
||||
t.Log(acturl)
|
||||
@@ -83,13 +79,12 @@ func TestBSTree_InOrderTraverse(t *testing.T) {
|
||||
func TestBSTree_LevelOrderTraverse(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestBSTree_LevelOrderTraverse")
|
||||
|
||||
bstree := NewBSTree(6)
|
||||
bstree := NewBSTree(6, &intComparator{})
|
||||
|
||||
comparator := &intComparator{}
|
||||
bstree.InsertNode(7, comparator)
|
||||
bstree.InsertNode(5, comparator)
|
||||
bstree.InsertNode(2, comparator)
|
||||
bstree.InsertNode(4, comparator)
|
||||
bstree.Insert(7)
|
||||
bstree.Insert(5)
|
||||
bstree.Insert(2)
|
||||
bstree.Insert(4)
|
||||
|
||||
bstree.Print()
|
||||
|
||||
@@ -98,20 +93,19 @@ func TestBSTree_LevelOrderTraverse(t *testing.T) {
|
||||
assert.Equal([]int{6, 5, 7, 2, 4}, acturl)
|
||||
}
|
||||
|
||||
func TestBSTree_DeletetNode(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestBSTree_DeletetNode")
|
||||
func TestBSTree_Delete(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestBSTree_Delete")
|
||||
|
||||
bstree := NewBSTree(6)
|
||||
bstree := NewBSTree(6, &intComparator{})
|
||||
|
||||
comparator := &intComparator{}
|
||||
bstree.InsertNode(7, comparator)
|
||||
bstree.InsertNode(5, comparator)
|
||||
bstree.InsertNode(2, comparator)
|
||||
bstree.InsertNode(4, comparator)
|
||||
bstree.Insert(7)
|
||||
bstree.Insert(5)
|
||||
bstree.Insert(2)
|
||||
bstree.Insert(4)
|
||||
|
||||
bstree.Print()
|
||||
|
||||
bstree.DeletetNode(4, comparator)
|
||||
bstree.Delete(4)
|
||||
bstree.Print()
|
||||
acturl1 := bstree.InOrderTraverse()
|
||||
t.Log(acturl1)
|
||||
@@ -128,15 +122,36 @@ func TestBSTree_DeletetNode(t *testing.T) {
|
||||
func TestBSTree_Depth(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestBSTree_Depth")
|
||||
|
||||
bstree := NewBSTree(6)
|
||||
bstree := NewBSTree(6, &intComparator{})
|
||||
|
||||
comparator := &intComparator{}
|
||||
bstree.InsertNode(7, comparator)
|
||||
bstree.InsertNode(5, comparator)
|
||||
bstree.InsertNode(2, comparator)
|
||||
bstree.InsertNode(4, comparator)
|
||||
bstree.Insert(7)
|
||||
bstree.Insert(5)
|
||||
bstree.Insert(2)
|
||||
bstree.Insert(4)
|
||||
|
||||
bstree.Print()
|
||||
|
||||
assert.Equal(bstree.Depth(), 4)
|
||||
}
|
||||
|
||||
func TestBSTree_IsSubTree(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestBSTree_IsSubTree")
|
||||
|
||||
superTree := NewBSTree(8, &intComparator{})
|
||||
superTree.Insert(4)
|
||||
superTree.Insert(5)
|
||||
superTree.Insert(6)
|
||||
superTree.Insert(9)
|
||||
superTree.Insert(4)
|
||||
|
||||
superTree.Print()
|
||||
|
||||
subTree := NewBSTree(5, &intComparator{})
|
||||
subTree.Insert(4)
|
||||
subTree.Insert(6)
|
||||
|
||||
subTree.Print()
|
||||
|
||||
assert.Equal(true, superTree.HasSubTree(subTree))
|
||||
assert.Equal(false, subTree.HasSubTree(superTree))
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
func preOrderTraverse[T any](node *datastructure.TreeNode[T]) []T {
|
||||
data := []T{}
|
||||
if node != nil {
|
||||
data = append(data, node.Data)
|
||||
data = append(data, node.Value)
|
||||
data = append(data, preOrderTraverse(node.Left)...)
|
||||
data = append(data, preOrderTraverse(node.Right)...)
|
||||
}
|
||||
@@ -23,7 +23,7 @@ func postOrderTraverse[T any](node *datastructure.TreeNode[T]) []T {
|
||||
if node != nil {
|
||||
data = append(data, preOrderTraverse(node.Left)...)
|
||||
data = append(data, preOrderTraverse(node.Right)...)
|
||||
data = append(data, node.Data)
|
||||
data = append(data, node.Value)
|
||||
}
|
||||
return data
|
||||
}
|
||||
@@ -32,7 +32,7 @@ func inOrderTraverse[T any](node *datastructure.TreeNode[T]) []T {
|
||||
data := []T{}
|
||||
if node != nil {
|
||||
data = append(data, inOrderTraverse(node.Left)...)
|
||||
data = append(data, node.Data)
|
||||
data = append(data, node.Value)
|
||||
data = append(data, inOrderTraverse(node.Right)...)
|
||||
}
|
||||
return data
|
||||
@@ -43,7 +43,7 @@ func preOrderPrint[T any](node *datastructure.TreeNode[T]) {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("%v, ", node.Data)
|
||||
fmt.Printf("%v, ", node.Value)
|
||||
preOrderPrint(node.Left)
|
||||
preOrderPrint(node.Right)
|
||||
}
|
||||
@@ -55,7 +55,7 @@ func postOrderPrint[T any](node *datastructure.TreeNode[T]) {
|
||||
|
||||
preOrderPrint(node.Left)
|
||||
preOrderPrint(node.Right)
|
||||
fmt.Printf("%v, ", node.Data)
|
||||
fmt.Printf("%v, ", node.Value)
|
||||
}
|
||||
|
||||
func inOrderPrint[T any](node *datastructure.TreeNode[T]) {
|
||||
@@ -64,7 +64,7 @@ func inOrderPrint[T any](node *datastructure.TreeNode[T]) {
|
||||
}
|
||||
|
||||
inOrderPrint(node.Left)
|
||||
fmt.Printf("%v, ", node.Data)
|
||||
fmt.Printf("%v, ", node.Value)
|
||||
inOrderPrint(node.Right)
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ func levelOrderTraverse[T any](root *datastructure.TreeNode[T], traversal *[]T)
|
||||
|
||||
for len(q) != 0 {
|
||||
n, q = q[0], q[1:]
|
||||
*traversal = append(*traversal, n.Data)
|
||||
*traversal = append(*traversal, n.Value)
|
||||
if n.Left != nil {
|
||||
q = append(q, n.Left)
|
||||
}
|
||||
@@ -87,7 +87,7 @@ func levelOrderTraverse[T any](root *datastructure.TreeNode[T], traversal *[]T)
|
||||
}
|
||||
|
||||
func insertTreeNode[T any](rootNode, newNode *datastructure.TreeNode[T], comparator lancetconstraints.Comparator) {
|
||||
if comparator.Compare(newNode.Data, rootNode.Data) == -1 {
|
||||
if comparator.Compare(newNode.Value, rootNode.Value) == -1 {
|
||||
if rootNode.Left == nil {
|
||||
rootNode.Left = newNode
|
||||
} else {
|
||||
@@ -107,9 +107,9 @@ func deleteTreeNode[T any](node *datastructure.TreeNode[T], data T, comparator l
|
||||
if node == nil {
|
||||
return nil
|
||||
}
|
||||
if comparator.Compare(data, node.Data) == -1 {
|
||||
if comparator.Compare(data, node.Value) == -1 {
|
||||
node.Left = deleteTreeNode(node.Left, data, comparator)
|
||||
} else if comparator.Compare(data, node.Data) == 1 {
|
||||
} else if comparator.Compare(data, node.Value) == 1 {
|
||||
node.Right = deleteTreeNode(node.Right, data, comparator)
|
||||
} else {
|
||||
if node.Left == nil {
|
||||
@@ -150,7 +150,7 @@ func printTreeNodes[T any](nodes []*datastructure.TreeNode[T], level, maxLevel i
|
||||
newNodes := []*datastructure.TreeNode[T]{}
|
||||
for _, node := range nodes {
|
||||
if node != nil {
|
||||
fmt.Printf("%v", node.Data)
|
||||
fmt.Printf("%v", node.Value)
|
||||
newNodes = append(newNodes, node.Left)
|
||||
newNodes = append(newNodes, node.Right)
|
||||
} else {
|
||||
@@ -216,6 +216,20 @@ func calculateDepth[T any](node *datastructure.TreeNode[T], depth int) int {
|
||||
return max(calculateDepth(node.Left, depth+1), calculateDepth(node.Right, depth+1))
|
||||
}
|
||||
|
||||
func isSubTree[T any](superTreeRoot, subTreeRoot *datastructure.TreeNode[T], comparator lancetconstraints.Comparator) bool {
|
||||
if subTreeRoot == nil {
|
||||
return true
|
||||
}
|
||||
if superTreeRoot == nil {
|
||||
return false
|
||||
}
|
||||
if comparator.Compare(superTreeRoot.Value, subTreeRoot.Value) != 0 {
|
||||
return false
|
||||
}
|
||||
res := isSubTree(superTreeRoot.Left, subTreeRoot.Left, comparator) && isSubTree(superTreeRoot.Right, subTreeRoot.Right, comparator)
|
||||
return res
|
||||
}
|
||||
|
||||
func max(a, b int) int {
|
||||
if a > b {
|
||||
return a
|
||||
|
||||
@@ -21,23 +21,20 @@ import (
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Index
|
||||
- [Algorithm](#algorithm)
|
||||
- [Source](#source)
|
||||
- [Usage](#usage)
|
||||
- [Index](#index)
|
||||
- [Documentation](#documentation)
|
||||
- [<span id="BubbleSort">BubbleSort</span>](#bubblesort)
|
||||
- [<span id="InsertionSort">InsertionSort</span>](#insertionsort)
|
||||
- [<span id="SelectionSort">SelectionSort</span>](#selectionsort)
|
||||
- [<span id="ShellSort">ShellSort</span>](#shellsort)
|
||||
- [<span id="QuickSort">QuickSort</span>](#quicksort)
|
||||
- [<span id="HeapSort">HeapSort</span>](#heapsort)
|
||||
- [<span id="MergeSort">MergeSort</span>](#mergesort)
|
||||
- [<span id="CountSort">CountSort</span>](#countsort)
|
||||
- [<span id="BinarySearch">BinarySearch</span>](#binarysearch)
|
||||
- [<span id="BinaryIterativeSearch">BinaryIterativeSearch</span>](#binaryiterativesearch)
|
||||
- [<span id="LinearSearch">LinearSearch</span>](#linearsearch)
|
||||
- [<span id="LRUCache">LRUCache</span>](#lrucache)
|
||||
- [BubbleSort](#BubbleSort)
|
||||
- [InsertionSort](#InsertionSort)
|
||||
- [SelectionSort](#SelectionSort)
|
||||
- [ShellSort](#ShellSort)
|
||||
- [QuickSort](#QuickSort)
|
||||
- [HeapSort](#HeapSort)
|
||||
- [MergeSort](#MergeSort)
|
||||
- [CountSort](#CountSort)
|
||||
- [BinarySearch](#BinarySearch)
|
||||
- [BinaryIterativeSearch](#BinaryIterativeSearch)
|
||||
|
||||
- [LinearSearch](#LinearSearch)
|
||||
- [LRUCache](#LRUCache)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
|
||||
@@ -21,23 +21,21 @@ import (
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 目录
|
||||
- [Algorithm](#algorithm)
|
||||
- [源码](#源码)
|
||||
- [用法](#用法)
|
||||
- [目录](#目录)
|
||||
- [文档](#文档)
|
||||
- [<span id="BubbleSort">BubbleSort</span>](#bubblesort)
|
||||
- [<span id="InsertionSort">InsertionSort</span>](#insertionsort)
|
||||
- [<span id="SelectionSort">SelectionSort</span>](#selectionsort)
|
||||
- [<span id="ShellSort">ShellSort</span>](#shellsort)
|
||||
- [<span id="QuickSort">QuickSort</span>](#quicksort)
|
||||
- [<span id="HeapSort">HeapSort</span>](#heapsort)
|
||||
- [<span id="MergeSort">MergeSort</span>](#mergesort)
|
||||
- [<span id="CountSort">CountSort</span>](#countsort)
|
||||
- [<span id="BinarySearch">BinarySearch</span>](#binarysearch)
|
||||
- [<span id="BinaryIterativeSearch">BinaryIterativeSearch</span>](#binaryiterativesearch)
|
||||
- [<span id="LinearSearch">LinearSearch</span>](#linearsearch)
|
||||
- [<span id="LRUCache">LRUCache</span>](#lrucache)
|
||||
|
||||
- [BubbleSort](#BubbleSort)
|
||||
- [InsertionSort](#InsertionSort)
|
||||
- [SelectionSort](#SelectionSort)
|
||||
- [ShellSort](#ShellSort)
|
||||
- [QuickSort](#QuickSort)
|
||||
- [HeapSort](#HeapSort)
|
||||
- [MergeSort](#MergeSort)
|
||||
|
||||
- [CountSort](#CountSort)
|
||||
- [BinarySearch](#BinarySearch)
|
||||
- [BinaryIterativeSearch](#BinaryIterativeSearch)
|
||||
- [LinearSearch](#LinearSearch)
|
||||
- [LRUCache](#LRUCache)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
|
||||
390
docs/concurrency.md
Normal file
390
docs/concurrency.md
Normal file
@@ -0,0 +1,390 @@
|
||||
# Concurrency
|
||||
Package concurrency contain some functions to support concurrent programming. eg, goroutine, channel, async.
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Source:
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/concurrency/channel.go](https://github.com/duke-git/lancet/blob/main/concurrency/channel.go)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Usage:
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/v2/concurrency"
|
||||
)
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Index
|
||||
### Channel
|
||||
- [NewChannel](#NewChannel)
|
||||
- [Bridge](#Bridge)
|
||||
- [FanIn](#FanIn)
|
||||
- [Generate](#Generate)
|
||||
- [Or](#Or)
|
||||
- [OrDone](#OrDone)
|
||||
- [Repeat](#Repeat)
|
||||
- [RepeatFn](#RepeatFn)
|
||||
- [Take](#Take)
|
||||
- [Tee](#Tee)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Documentation
|
||||
|
||||
|
||||
## Channel
|
||||
### <span id="NewChannel">NewChannel</span>
|
||||
<p>return a Channel pointer instance.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
type Channel struct {}
|
||||
func NewChannel() *Channel
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/concurrency"
|
||||
)
|
||||
|
||||
func main() {
|
||||
c := concurrency.NewChannel()
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Bridge">Bridge</span>
|
||||
|
||||
<p>Link multiple channels into one channel until cancel the context.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) Bridge(ctx context.Context, chanStream <-chan <-chan any) <-chan any
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/concurrency"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
genVals := func() <-chan <-chan any {
|
||||
chanStream := make(chan (<-chan any))
|
||||
go func() {
|
||||
defer close(chanStream)
|
||||
for i := 0; i < 10; i++ {
|
||||
stream := make(chan any, 1)
|
||||
stream <- i
|
||||
close(stream)
|
||||
chanStream <- stream
|
||||
}
|
||||
}()
|
||||
return chanStream
|
||||
}
|
||||
|
||||
index := 0
|
||||
for val := range c.Bridge(ctx, genVals()) {
|
||||
fmt.Printf("%v ", val) //0 1 2 3 4 5 6 7 8 9
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="FanIn">FanIn</span>
|
||||
|
||||
<p>merge multiple channels into one channel until cancel the context.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) FanIn(ctx context.Context, channels ...<-chan any) <-chan any
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/concurrency"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
channels := make([]<-chan any, 3)
|
||||
|
||||
for i := 0; i < 3; i++ {
|
||||
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 3)
|
||||
}
|
||||
|
||||
mergedChannel := c.FanIn(ctx, channels...)
|
||||
|
||||
for val := range mergedChannel {
|
||||
fmt.Println("\t%d\n", val) //1,2,1,0,0,1,0,2,2 (order not for sure)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="Repeat">Repeat</span>
|
||||
|
||||
<p>Return a chan, put param `values` into the chan repeatly until cancel the context.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) Repeat(ctx context.Context, values ...any) <-chan any
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/concurrency"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 5)
|
||||
|
||||
for v := range intStream {
|
||||
fmt.Println(v) //1, 2, 1, 2, 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="RepeatFn">RepeatFn</span>
|
||||
|
||||
<p>Return a chan, excutes fn repeatly, and put the result into retruned chan until cancel context.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) RepeatFn(ctx context.Context, fn func() any) <-chan any
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/concurrency"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
fn := func() any {
|
||||
s := "a"
|
||||
return s
|
||||
}
|
||||
c := concurrency.NewChannel()
|
||||
dataStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3)
|
||||
|
||||
for v := range dataStream {
|
||||
fmt.Println(v) //a, a, a
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Or">Or</span>
|
||||
|
||||
<p>Read one or more channels into one channel, will close when any readin channel is closed.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) Or(channels ...<-chan any) <-chan any
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/concurrency"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sig := func(after time.Duration) <-chan any {
|
||||
c := make(chan interface{})
|
||||
go func() {
|
||||
defer close(c)
|
||||
time.Sleep(after)
|
||||
}()
|
||||
return c
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
<-c.Or(
|
||||
sig(1*time.Second),
|
||||
sig(2*time.Second),
|
||||
sig(3*time.Second),
|
||||
sig(4*time.Second),
|
||||
sig(5*time.Second),
|
||||
)
|
||||
|
||||
fmt.Println("done after %v", time.Since(start)) //1.003s
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="OrDone">OrDone</span>
|
||||
|
||||
<p>Read a channel into another channel, will close until cancel context.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) OrDone(ctx context.Context, channel <-chan any) <-chan any
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/concurrency"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1), 3)
|
||||
|
||||
for val := range c.OrDone(ctx, intStream) {
|
||||
fmt.Println(val) //1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Take">Take</span>
|
||||
|
||||
<p>Return a chan whose values are tahken from another chan until cancel context.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) Take(ctx context.Context, valueStream <-chan any, number int) <-chan any
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/concurrency"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
numbers := make(chan any, 5)
|
||||
numbers <- 1
|
||||
numbers <- 2
|
||||
numbers <- 3
|
||||
numbers <- 4
|
||||
numbers <- 5
|
||||
defer close(numbers)
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
intStream := c.Take(ctx, numbers, 3)
|
||||
|
||||
for val := range intStream {
|
||||
fmt.Println(val) //1, 2, 3
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Tee">Tee</span>
|
||||
|
||||
<p>Split one chanel into two channels until cancel context.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) Tee(ctx context.Context, in <-chan any) (<-chan any, <-chan any)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/concurrency"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
inStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 4)
|
||||
|
||||
out1, out2 := c.Tee(ctx, inStream)
|
||||
for val := range out1 {
|
||||
fmt.Println(val) //1
|
||||
fmt.Println(<-out2) //1
|
||||
}
|
||||
}
|
||||
```
|
||||
390
docs/concurrency_zh-CN.md
Normal file
390
docs/concurrency_zh-CN.md
Normal file
@@ -0,0 +1,390 @@
|
||||
# Concurrency
|
||||
并发包包含一些支持并发编程的功能。例如:goroutine, channel, async等。
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 源码:
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/concurrency/channel.go](https://github.com/duke-git/lancet/blob/main/concurrency/channel.go)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 用法:
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/v2/concurrency"
|
||||
)
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 目录
|
||||
### Channel
|
||||
- [NewChannel](#NewChannel)
|
||||
- [Bridge](#Bridge)
|
||||
- [FanIn](#FanIn)
|
||||
- [Generate](#Generate)
|
||||
- [Or](#Or)
|
||||
- [OrDone](#OrDone)
|
||||
- [Repeat](#Repeat)
|
||||
- [RepeatFn](#RepeatFn)
|
||||
- [Take](#Take)
|
||||
- [Tee](#Tee)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 文档
|
||||
|
||||
|
||||
### Channel
|
||||
### <span id="NewChannel">NewChannel</span>
|
||||
<p>返回一个 Channel 指针实例</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
type Channel struct {}
|
||||
func NewChannel() *Channel
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/concurrency"
|
||||
)
|
||||
|
||||
func main() {
|
||||
c := concurrency.NewChannel()
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Bridge">Bridge</span>
|
||||
|
||||
<p>将多个通道链接到一个通道,直到取消上下文。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) Bridge(ctx context.Context, chanStream <-chan <-chan any) <-chan any
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/concurrency"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
genVals := func() <-chan <-chan any {
|
||||
chanStream := make(chan (<-chan any))
|
||||
go func() {
|
||||
defer close(chanStream)
|
||||
for i := 0; i < 10; i++ {
|
||||
stream := make(chan any, 1)
|
||||
stream <- i
|
||||
close(stream)
|
||||
chanStream <- stream
|
||||
}
|
||||
}()
|
||||
return chanStream
|
||||
}
|
||||
|
||||
index := 0
|
||||
for val := range c.Bridge(ctx, genVals()) {
|
||||
fmt.Printf("%v ", val) //0 1 2 3 4 5 6 7 8 9
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="FanIn">FanIn</span>
|
||||
|
||||
<p>将多个通道合并为一个通道,直到取消上下文</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) FanIn(ctx context.Context, channels ...<-chan any) <-chan any
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/concurrency"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
channels := make([]<-chan any, 3)
|
||||
|
||||
for i := 0; i < 3; i++ {
|
||||
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 3)
|
||||
}
|
||||
|
||||
mergedChannel := c.FanIn(ctx, channels...)
|
||||
|
||||
for val := range mergedChannel {
|
||||
fmt.Println("\t%d\n", val) //1,2,1,0,0,1,0,2,2 (order not for sure)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="Repeat">Repeat</span>
|
||||
|
||||
<p>返回一个chan,将参数`values`重复放入chan,直到取消上下文。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) Repeat(ctx context.Context, values ...any) <-chan any
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/concurrency"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 5)
|
||||
|
||||
for v := range intStream {
|
||||
fmt.Println(v) //1, 2, 1, 2, 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="RepeatFn">RepeatFn</span>
|
||||
|
||||
<p>返回一个chan,重复执行函数fn,并将结果放入返回的chan,直到取消上下文。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) RepeatFn(ctx context.Context, fn func() any) <-chan any
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/concurrency"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
fn := func() any {
|
||||
s := "a"
|
||||
return s
|
||||
}
|
||||
c := concurrency.NewChannel()
|
||||
dataStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3)
|
||||
|
||||
for v := range dataStream {
|
||||
fmt.Println(v) //a, a, a
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Or">Or</span>
|
||||
|
||||
<p>将一个或多个通道读取到一个通道中,当任何读取通道关闭时将结束读取。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) Or(channels ...<-chan any) <-chan any
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/concurrency"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sig := func(after time.Duration) <-chan any {
|
||||
c := make(chan interface{})
|
||||
go func() {
|
||||
defer close(c)
|
||||
time.Sleep(after)
|
||||
}()
|
||||
return c
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
<-c.Or(
|
||||
sig(1*time.Second),
|
||||
sig(2*time.Second),
|
||||
sig(3*time.Second),
|
||||
sig(4*time.Second),
|
||||
sig(5*time.Second),
|
||||
)
|
||||
|
||||
fmt.Println("done after %v", time.Since(start)) //1.003s
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="OrDone">OrDone</span>
|
||||
|
||||
<p>将一个通道读入另一个通道,直到取消上下文。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) OrDone(ctx context.Context, channel <-chan any) <-chan any
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/concurrency"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1), 3)
|
||||
|
||||
for val := range c.OrDone(ctx, intStream) {
|
||||
fmt.Println(val) //1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Take">Take</span>
|
||||
|
||||
<p>返回一个chan,其值从另一个chan获取,直到取消上下文。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) Take(ctx context.Context, valueStream <-chan any, number int) <-chan any
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/concurrency"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
numbers := make(chan any, 5)
|
||||
numbers <- 1
|
||||
numbers <- 2
|
||||
numbers <- 3
|
||||
numbers <- 4
|
||||
numbers <- 5
|
||||
defer close(numbers)
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
intStream := c.Take(ctx, numbers, 3)
|
||||
|
||||
for val := range intStream {
|
||||
fmt.Println(val) //1, 2, 3
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Tee">Tee</span>
|
||||
|
||||
<p>将一个通道分成两个通道,直到取消上下文。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) Tee(ctx context.Context, in <-chan any) (<-chan any, <-chan any)
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/concurrency"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
inStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 4)
|
||||
|
||||
out1, out2 := c.Tee(ctx, inStream)
|
||||
for val := range out1 {
|
||||
fmt.Println(val) //1
|
||||
fmt.Println(<-out2) //1
|
||||
}
|
||||
}
|
||||
```
|
||||
1019
docs/datastructure/linklist.md
Normal file
1019
docs/datastructure/linklist.md
Normal file
File diff suppressed because it is too large
Load Diff
1019
docs/datastructure/linklist_zh-CN.md
Normal file
1019
docs/datastructure/linklist_zh-CN.md
Normal file
File diff suppressed because it is too large
Load Diff
713
docs/datastructure/list.md
Normal file
713
docs/datastructure/list.md
Normal file
@@ -0,0 +1,713 @@
|
||||
# List
|
||||
List is a linear table, implemented with slice.
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Source
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/datastructure/list/list.go](https://github.com/duke-git/lancet/blob/main/datastructure/list/list.go)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Usage
|
||||
```go
|
||||
import (
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Index
|
||||
|
||||
- [NewList](#NewList)
|
||||
- [Contain](#Contain)
|
||||
- [Data](#Data)
|
||||
- [ValueOf](#ValueOf)
|
||||
- [IndexOf](#IndexOf)
|
||||
- [Push](#Push)
|
||||
- [PopFirst](#PopFirst)
|
||||
- [PopLast](#PopLast)
|
||||
- [DeleteAt](#DeleteAt)
|
||||
- [InsertAt](#InsertAt)
|
||||
- [UpdateAt](#UpdateAt)
|
||||
- [Equal](#Equal)
|
||||
- [IsEmpty](#IsEmpty)
|
||||
- [Clear](#Clear)
|
||||
- [Clone](#Clone)
|
||||
- [Merge](#Merge)
|
||||
- [Size](#Size)
|
||||
- [Swap](#Swap)
|
||||
- [Reverse](#Reverse)
|
||||
- [Unique](#Unique)
|
||||
- [Union](#Union)
|
||||
- [Intersection](#Intersection)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Documentation
|
||||
|
||||
### <span id="NewList">NewList</span>
|
||||
<p>List is a linear table, implemented with slice.
|
||||
NewList function return a list pointer</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
type List[T any] struct {
|
||||
data []T
|
||||
}
|
||||
func NewList[T any](data []T) *List[T]
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li := list.NewList([]int{1, 2, 3})
|
||||
fmt.Println(li)
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Contain">Contain</span>
|
||||
<p>Check if the value in the list or not</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (l *List[T]) Contain(value T) bool
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li := list.NewList([]int{1, 2, 3})
|
||||
|
||||
fmt.Println(li.Contain(1)) //true
|
||||
fmt.Println(li.Contain(0)) //false
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Data">Data</span>
|
||||
<p>Return slice of list data</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (l *List[T]) Data() []T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li := list.NewList([]int{1, 2, 3})
|
||||
data := li.Data()
|
||||
|
||||
fmt.Println(data) //[]int{1, 2, 3}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="ValueOf">ValueOf</span>
|
||||
<p>Return the value pointer at index in list</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (l *List[T]) ValueOf(index int) (*T, bool)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li := list.NewList([]int{1, 2, 3})
|
||||
v, ok := li.ValueOf(0)
|
||||
|
||||
fmt.Println(*v) //1
|
||||
fmt.Println(ok) //true
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="IndexOf">IndexOf</span>
|
||||
<p>Reture the index of value in the list. if not found return -1</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (l *List[T]) IndexOf(value T) int
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li := list.NewList([]int{1, 2, 3})
|
||||
|
||||
fmt.Println(li.IndexOf(1)) //0
|
||||
fmt.Println(li.IndexOf(0)) //-1
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Push">Push</span>
|
||||
<p>Append value to the list</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (l *List[T]) Push(value T)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li := list.NewList([]int{1, 2, 3})
|
||||
li.Push(4)
|
||||
|
||||
fmt.Println(li.Data()) //[]int{1, 2, 3, 4}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="PopFirst">PopFirst</span>
|
||||
<p>Delete the first value of list and return it</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (l *List[T]) PopFirst() (*T, bool)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li := list.NewList([]int{1, 2, 3})
|
||||
v, ok := li.PopFirst()
|
||||
|
||||
fmt.Println(*v) //1
|
||||
fmt.Println(ok) //true
|
||||
fmt.Println(li.Data()) //2, 3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="PopLast">PopFirst</span>
|
||||
<p>Delete the last value of list and return it</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (l *List[T]) PopLast() (*T, bool)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li := list.NewList([]int{1, 2, 3})
|
||||
v, ok := li.PopLast()
|
||||
|
||||
fmt.Println(*v) //3
|
||||
fmt.Println(ok) //true
|
||||
fmt.Println(li.Data()) //1, 2
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="DeleteAt">DeleteAt</span>
|
||||
<p>Delete the value of list at index, if index is not between 0 and length of list data, do nothing</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (l *List[T]) DeleteAt(index int)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li := list.NewList([]int{1, 2, 3, 4})
|
||||
|
||||
li.DeleteAt(-1)
|
||||
fmt.Println(li.Data()) //1,2,3,4
|
||||
|
||||
li.DeleteAt(4)
|
||||
fmt.Println(li.Data()) //1,2,3,4
|
||||
|
||||
li.DeleteAt(0)
|
||||
fmt.Println(li.Data()) //2,3,4
|
||||
|
||||
li.DeleteAt(2)
|
||||
fmt.Println(li.Data()) //2,3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="InsertAt">InsertAt</span>
|
||||
<p>Insert value into list at index, if index is not between 0 and length of list data, do nothing</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (l *List[T]) InsertAt(index int, value T)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li := list.NewList([]int{1, 2, 3})
|
||||
|
||||
li.InsertAt(-1, 0)
|
||||
fmt.Println(li.Data()) //1,2,3
|
||||
|
||||
li.InsertAt(4, 0)
|
||||
fmt.Println(li.Data()) //1,2,3
|
||||
|
||||
li.InsertAt(3, 4)
|
||||
fmt.Println(li.Data()) //1,2,3,4
|
||||
|
||||
// li.InsertAt(2, 4)
|
||||
// fmt.Println(li.Data()) //1,2,4,3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="UpdateAt">UpdateAt</span>
|
||||
<p>Update value of list at index, index shoud between 0 and list size - 1</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (l *List[T]) UpdateAt(index int, value T)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li := list.NewList([]int{1, 2, 3})
|
||||
|
||||
li.UpdateAt(-1, 0)
|
||||
fmt.Println(li.Data()) //1,2,3
|
||||
|
||||
li.UpdateAt(2, 4)
|
||||
fmt.Println(li.Data()) //1,2,4
|
||||
|
||||
li.UpdateAt(3, 5)
|
||||
fmt.Println(li.Data()) //1,2,4
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="Equal">Equal</span>
|
||||
<p>Compare a list to another list, use reflect.DeepEqual on every element</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (l *List[T]) Equal(other *List[T]) bool
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li1 := list.NewList([]int{1, 2, 3, 4})
|
||||
li2 := list.NewList([]int{1, 2, 3, 4})
|
||||
li3 := list.NewList([]int{1, 2, 3})
|
||||
|
||||
fmt.Println(li1.Equal(li2)) //true
|
||||
fmt.Println(li1.Equal(li3)) //false
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="IsEmpty">IsEmpty</span>
|
||||
<p>Check if a list is empty or not</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (l *List[T]) IsEmpty() bool
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li1 := list.NewList([]int{1, 2, 3})
|
||||
li2 := list.NewList([]int{})
|
||||
|
||||
fmt.Println(li1.IsEmpty()) //false
|
||||
fmt.Println(li2.IsEmpty()) //true
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Clear">Clear</span>
|
||||
<p>Clear the data of list</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (l *List[T]) Clear()
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li := list.NewList([]int{1, 2, 3})
|
||||
li.Clear()
|
||||
|
||||
fmt.Println(li.Data()) // empty
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Clone">Clone</span>
|
||||
<p>Return a copy of list</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (l *List[T]) Clone() *List[T]
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li := list.NewList([]int{1, 2, 3})
|
||||
cloneList := li.Clone()
|
||||
|
||||
fmt.Println(cloneList.Data()) // 1,2,3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Merge">Merge</span>
|
||||
<p>Merge two list, return new list, don't change original list</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (l *List[T]) Merge(other *List[T]) *List[T]
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li1 := list.NewList([]int{1, 2, 3, 4})
|
||||
li2 := list.NewList([]int{4, 5, 6})
|
||||
li3 := li1.Merge(li2)
|
||||
|
||||
fmt.Println(li3.Data()) //1, 2, 3, 4, 4, 5, 6
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Size">Size</span>
|
||||
<p>Return number of list data items</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (l *List[T]) Size() int
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li := list.NewList([]int{1, 2, 3, 4})
|
||||
|
||||
fmt.Println(li.Size()) //4
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Swap">Swap</span>
|
||||
<p>Swap the value at two index in list</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (l *List[T]) Swap(i, j int)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li := list.NewList([]int{1, 2, 3, 4})
|
||||
li.Swap(0, 3)
|
||||
|
||||
fmt.Println(li.Data()) //4, 2, 3, 1
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Reverse">Reverse</span>
|
||||
<p>Reverse the data item order of list</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (l *List[T]) Reverse()
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li := list.NewList([]int{1, 2, 3, 4})
|
||||
li.Reverse()
|
||||
|
||||
fmt.Println(li.Data()) //4, 3, 2, 1
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Unique">Unique</span>
|
||||
<p>Remove duplicate items in list</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (l *List[T]) Unique()
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li := list.NewList([]int{1, 2, 2, 3, 4})
|
||||
li.Unique()
|
||||
|
||||
fmt.Println(li.Data()) //1,2,3,4
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Union">Union</span>
|
||||
<p>Creates a new list contain all elements in list l and other, remove duplicate element</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (l *List[T]) Union(other *List[T]) *List[T]
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li1 := list.NewList([]int{1, 2, 3, 4})
|
||||
li2 := list.NewList([]int{4, 5, 6})
|
||||
li3 := li1.Union(li2)
|
||||
|
||||
fmt.Println(li3.Data()) //1,2,3,4,5,6
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Intersection">Intersection</span>
|
||||
<p>Creates a new list whose element both be contained in list l and other</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (l *List[T]) Intersection(other *List[T]) *List[T]
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li1 := list.NewList([]int{1, 2, 3, 4})
|
||||
li2 := list.NewList([]int{4, 5, 6})
|
||||
li3 := li1.Intersection(li2)
|
||||
|
||||
fmt.Println(li3.Data()) //4
|
||||
}
|
||||
```
|
||||
712
docs/datastructure/list_zh-CN.md
Normal file
712
docs/datastructure/list_zh-CN.md
Normal file
@@ -0,0 +1,712 @@
|
||||
# List
|
||||
List是线性表数据结构, 用go切片实现。
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 源码
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/datastructure/list/list.go](https://github.com/duke-git/lancet/blob/main/datastructure/list/list.go)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 用法
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/v2/datastructure"
|
||||
)
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 目录
|
||||
|
||||
- [NewList](#NewList)
|
||||
- [Contain](#Contain)
|
||||
- [Data](#Data)
|
||||
- [ValueOf](#ValueOf)
|
||||
- [IndexOf](#IndexOf)
|
||||
- [Push](#Push)
|
||||
- [PopFirst](#PopFirst)
|
||||
- [PopLast](#PopLast)
|
||||
- [DeleteAt](#DeleteAt)
|
||||
- [InsertAt](#InsertAt)
|
||||
- [UpdateAt](#UpdateAt)
|
||||
- [Equal](#Equal)
|
||||
- [IsEmpty](#IsEmpty)
|
||||
- [Clear](#Clear)
|
||||
- [Clone](#Clone)
|
||||
- [Merge](#Merge)
|
||||
- [Size](#Size)
|
||||
- [Swap](#Swap)
|
||||
- [Reverse](#Reverse)
|
||||
- [Unique](#Unique)
|
||||
- [Union](#Union)
|
||||
- [Intersection](#Intersection)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 文档
|
||||
|
||||
### <span id="NewList">NewList</span>
|
||||
<p>返回List指针实例</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
type List[T any] struct {
|
||||
data []T
|
||||
}
|
||||
func NewList[T any](data []T) *List[T]
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li := list.NewList([]int{1, 2, 3})
|
||||
fmt.Println(li)
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Contain">Contain</span>
|
||||
<p>判断列表中是否包含特定值</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (l *List[T]) Contain(value T) bool
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li := list.NewList([]int{1, 2, 3})
|
||||
|
||||
fmt.Println(li.Contain(1)) //true
|
||||
fmt.Println(li.Contain(0)) //false
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Data">Data</span>
|
||||
<p>返回List中所有数据(切片)</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (l *List[T]) Data() []T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li := list.NewList([]int{1, 2, 3})
|
||||
data := li.Data()
|
||||
|
||||
fmt.Println(data) //[]int{1, 2, 3}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="ValueOf">ValueOf</span>
|
||||
<p>返回列表中索引处的值指针</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (l *List[T]) ValueOf(index int) (*T, bool)
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li := list.NewList([]int{1, 2, 3})
|
||||
v, ok := li.ValueOf(0)
|
||||
|
||||
fmt.Println(*v) //1
|
||||
fmt.Println(ok) //true
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="IndexOf">IndexOf</span>
|
||||
<p>返回列表中值的索引,如果没有找到返回-1</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (l *List[T]) IndexOf(value T) int
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li := list.NewList([]int{1, 2, 3})
|
||||
|
||||
fmt.Println(li.IndexOf(1)) //0
|
||||
fmt.Println(li.IndexOf(0)) //-1
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Push">Push</span>
|
||||
<p>将值附加到列表末尾</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (l *List[T]) Push(value T)
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li := list.NewList([]int{1, 2, 3})
|
||||
li.Push(4)
|
||||
|
||||
fmt.Println(li.Data()) //[]int{1, 2, 3, 4}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="PopFirst">PopFirst</span>
|
||||
<p>删除列表的第一个值并返回该值</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (l *List[T]) PopFirst() (*T, bool)
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li := list.NewList([]int{1, 2, 3})
|
||||
v, ok := li.PopFirst()
|
||||
|
||||
fmt.Println(*v) //1
|
||||
fmt.Println(ok) //true
|
||||
fmt.Println(li.Data()) //2, 3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="PopLast">PopFirst</span>
|
||||
<p>删除列表的最后一个值并返回该值</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (l *List[T]) PopLast() (*T, bool)
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li := list.NewList([]int{1, 2, 3})
|
||||
v, ok := li.PopLast()
|
||||
|
||||
fmt.Println(*v) //3
|
||||
fmt.Println(ok) //true
|
||||
fmt.Println(li.Data()) //1, 2
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="DeleteAt">DeleteAt</span>
|
||||
<p>删除索引处列表的值,如果索引不在0和列表数据长度之间,则不执行任何操作</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (l *List[T]) DeleteAt(index int)
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li := list.NewList([]int{1, 2, 3, 4})
|
||||
|
||||
li.DeleteAt(-1)
|
||||
fmt.Println(li.Data()) //1,2,3,4
|
||||
|
||||
li.DeleteAt(4)
|
||||
fmt.Println(li.Data()) //1,2,3,4
|
||||
|
||||
li.DeleteAt(0)
|
||||
fmt.Println(li.Data()) //2,3,4
|
||||
|
||||
li.DeleteAt(2)
|
||||
fmt.Println(li.Data()) //2,3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="InsertAt">InsertAt</span>
|
||||
<p>在索引处插入值到列表中,如果索引不在 0 和列表数据长度之间,则不执行任何操作</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (l *List[T]) InsertAt(index int, value T)
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li := list.NewList([]int{1, 2, 3})
|
||||
|
||||
li.InsertAt(-1, 0)
|
||||
fmt.Println(li.Data()) //1,2,3
|
||||
|
||||
li.InsertAt(4, 0)
|
||||
fmt.Println(li.Data()) //1,2,3
|
||||
|
||||
li.InsertAt(3, 4)
|
||||
fmt.Println(li.Data()) //1,2,3,4
|
||||
|
||||
// li.InsertAt(2, 4)
|
||||
// fmt.Println(li.Data()) //1,2,4,3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="UpdateAt">UpdateAt</span>
|
||||
<p>更新索引处列表的值,索引应该在0和列表数据长度-1之间</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (l *List[T]) UpdateAt(index int, value T)
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li := list.NewList([]int{1, 2, 3})
|
||||
|
||||
li.UpdateAt(-1, 0)
|
||||
fmt.Println(li.Data()) //1,2,3
|
||||
|
||||
li.UpdateAt(2, 4)
|
||||
fmt.Println(li.Data()) //1,2,4
|
||||
|
||||
li.UpdateAt(3, 5)
|
||||
fmt.Println(li.Data()) //1,2,4
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="Equal">Equal</span>
|
||||
<p>比较一个列表和另一个列表,在每个元素上使用 reflect.DeepEqual</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (l *List[T]) Equal(other *List[T]) bool
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li1 := list.NewList([]int{1, 2, 3, 4})
|
||||
li2 := list.NewList([]int{1, 2, 3, 4})
|
||||
li3 := list.NewList([]int{1, 2, 3})
|
||||
|
||||
fmt.Println(li1.Equal(li2)) //true
|
||||
fmt.Println(li1.Equal(li3)) //false
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="IsEmpty">IsEmpty</span>
|
||||
<p>判断列表是否为空</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (l *List[T]) IsEmpty() bool
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li1 := list.NewList([]int{1, 2, 3})
|
||||
li2 := list.NewList([]int{})
|
||||
|
||||
fmt.Println(li1.IsEmpty()) //false
|
||||
fmt.Println(li2.IsEmpty()) //true
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Clear">Clear</span>
|
||||
<p>清空列表数据</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (l *List[T]) Clear()
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li := list.NewList([]int{1, 2, 3})
|
||||
li.Clear()
|
||||
|
||||
fmt.Println(li.Data()) // empty
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Clone">Clone</span>
|
||||
<p>返回列表的一个拷贝</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (l *List[T]) Clone() *List[T]
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li := list.NewList([]int{1, 2, 3})
|
||||
cloneList := li.Clone()
|
||||
|
||||
fmt.Println(cloneList.Data()) // 1,2,3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Merge">Merge</span>
|
||||
<p>合并两个列表,返回新的列表</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (l *List[T]) Merge(other *List[T]) *List[T]
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li1 := list.NewList([]int{1, 2, 3, 4})
|
||||
li2 := list.NewList([]int{4, 5, 6})
|
||||
li3 := li1.Merge(li2)
|
||||
|
||||
fmt.Println(li3.Data()) //1, 2, 3, 4, 4, 5, 6
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Size">Size</span>
|
||||
<p>返回列表数据项的数量</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (l *List[T]) Size() int
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li := list.NewList([]int{1, 2, 3, 4})
|
||||
|
||||
fmt.Println(li.Size()) //4
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Swap">Swap</span>
|
||||
<p>交换列表中两个索引位置的值</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (l *List[T]) Swap(i, j int)
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li := list.NewList([]int{1, 2, 3, 4})
|
||||
li.Swap(0, 3)
|
||||
|
||||
fmt.Println(li.Data()) //4, 2, 3, 1
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Reverse">Reverse</span>
|
||||
<p>反转列表的数据项顺序</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (l *List[T]) Reverse()
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li := list.NewList([]int{1, 2, 3, 4})
|
||||
li.Reverse()
|
||||
|
||||
fmt.Println(li.Data()) //4, 3, 2, 1
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Unique">Unique</span>
|
||||
<p>列表去除重复数据项</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (l *List[T]) Unique()
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li := list.NewList([]int{1, 2, 2, 3, 4})
|
||||
li.Unique()
|
||||
|
||||
fmt.Println(li.Data()) //1,2,3,4
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Union">Union</span>
|
||||
<p>两个列表取并集,去除重复数据项</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (l *List[T]) Union(other *List[T]) *List[T]
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li1 := list.NewList([]int{1, 2, 3, 4})
|
||||
li2 := list.NewList([]int{4, 5, 6})
|
||||
li3 := li1.Union(li2)
|
||||
|
||||
fmt.Println(li3.Data()) //1,2,3,4,5,6
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Intersection">Intersection</span>
|
||||
<p>两个列表取交集</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (l *List[T]) Intersection(other *List[T]) *List[T]
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
li1 := list.NewList([]int{1, 2, 3, 4})
|
||||
li2 := list.NewList([]int{4, 5, 6})
|
||||
li3 := li1.Intersection(li2)
|
||||
|
||||
fmt.Println(li3.Data()) //4
|
||||
}
|
||||
```
|
||||
1387
docs/datastructure/queue.md
Normal file
1387
docs/datastructure/queue.md
Normal file
File diff suppressed because it is too large
Load Diff
1387
docs/datastructure/queue_zh-CN.md
Normal file
1387
docs/datastructure/queue_zh-CN.md
Normal file
File diff suppressed because it is too large
Load Diff
489
docs/datastructure/set.md
Normal file
489
docs/datastructure/set.md
Normal file
@@ -0,0 +1,489 @@
|
||||
# Set
|
||||
Set is a data container, like list, but elements of set is not duplicate.
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Source
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/datastructure/set/set.go](https://github.com/duke-git/lancet/blob/main/datastructure/set/set.go)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Usage
|
||||
```go
|
||||
import (
|
||||
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||
)
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Index
|
||||
|
||||
- [NewSet](#NewSet)
|
||||
- [Values](#Values)
|
||||
- [Add](#Add)
|
||||
- [Delete](#Delete)
|
||||
- [Contain](#Contain)
|
||||
- [ContainAll](#ContainAll)
|
||||
- [Clone](#Clone)
|
||||
- [Size](#Size)
|
||||
- [Equal](#Equal)
|
||||
- [Iterate](#Iterate)
|
||||
- [IsEmpty](#IsEmpty)
|
||||
- [Union](#Union)
|
||||
- [Intersection](#Intersection)
|
||||
|
||||
- [SymmetricDifference](#SymmetricDifference)
|
||||
- [Minus](#Minus)
|
||||
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Documentation
|
||||
|
||||
### <span id="NewSet">NewSet</span>
|
||||
<p>Make a Set instance</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
type Set[T comparable] map[T]bool
|
||||
func NewSet[T comparable](values ...T) Set[T]
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||
)
|
||||
|
||||
func main() {
|
||||
st := set.NewSet[int](1,2,2,3)
|
||||
fmt.Println(st.Values()) //1,2,3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Values">Values</span>
|
||||
<p>Return slice of all set data</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s Set[T]) Values() []T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||
)
|
||||
|
||||
func main() {
|
||||
st := set.NewSet[int](1,2,2,3)
|
||||
fmt.Println(st.Values()) //1,2,3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Add">Add</span>
|
||||
<p>Add value to set</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s Set[T]) Add(values ...T)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||
)
|
||||
|
||||
func main() {
|
||||
st := set.NewSet[int]()
|
||||
st.Add(1, 2, 3)
|
||||
|
||||
fmt.Println(st.Values()) //1,2,3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Delete">Delete</span>
|
||||
<p>Delete value in set</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s Set[T]) Delete(values ...T)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||
)
|
||||
|
||||
func main() {
|
||||
st := set.NewSet[int]()
|
||||
st.Add(1, 2, 3)
|
||||
|
||||
set.Delete(3)
|
||||
fmt.Println(st.Values()) //1,2
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Contain">Contain</span>
|
||||
<p>Check if value is in set or not</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s Set[T]) Contain(value T) bool
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||
)
|
||||
|
||||
func main() {
|
||||
st := set.NewSet[int]()
|
||||
st.Add(1, 2, 3)
|
||||
|
||||
fmt.Println(st.Contain(1)) //true
|
||||
fmt.Println(st.Contain(4)) //false
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="ContainAll">ContainAll</span>
|
||||
<p>Checks if set contains another set</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s Set[T]) ContainAll(other Set[T]) bool
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||
)
|
||||
|
||||
func main() {
|
||||
set1 := set.NewSet(1, 2, 3)
|
||||
set2 := set.NewSet(1, 2)
|
||||
set3 := set.NewSet(1, 2, 3, 4)
|
||||
|
||||
fmt.Println(set1.ContainAll(set2)) //true
|
||||
fmt.Println(set1.ContainAll(set3)) //false
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Size">Size</span>
|
||||
<p>Get the number of elements in set</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s Set[T]) Size() int
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||
)
|
||||
|
||||
func main() {
|
||||
set1 := set.NewSet(1, 2, 3)
|
||||
|
||||
fmt.Println(set1.Size()) //3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Clone">Clone</span>
|
||||
<p>Make a copy of set</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s Set[T]) Clone() Set[T]
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||
)
|
||||
|
||||
func main() {
|
||||
set1 := set.NewSet(1, 2, 3)
|
||||
set2 := set1.Clone()
|
||||
|
||||
fmt.Println(set1.Size() == set2.Size()) //true
|
||||
fmt.Println(set1.ContainAll(set2)) //true
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Equal">Equal</span>
|
||||
<p>Check if two sets has same elements or not</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s Set[T]) Equal(other Set[T]) bool
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||
)
|
||||
|
||||
func main() {
|
||||
set1 := set.NewSet(1, 2, 3)
|
||||
set2 := set.NewSet(1, 2, 3)
|
||||
set3 := set.NewSet(1, 2, 3, 4)
|
||||
|
||||
fmt.Println(set1.Equal(set2)) //true
|
||||
fmt.Println(set1.Equal(set3)) //false
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Iterate">Iterate</span>
|
||||
<p>Call function by every element of set</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s Set[T]) Iterate(fn func(value T))
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||
)
|
||||
|
||||
func main() {
|
||||
set1 := set.NewSet(1, 2, 3)
|
||||
arr := []int{}
|
||||
set.Iterate(func(value int) {
|
||||
arr = append(arr, value)
|
||||
})
|
||||
|
||||
fmt.Println(arr) //1,2,3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="IsEmpty">IsEmpty</span>
|
||||
<p>Check if the set is empty or not</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s Set[T]) IsEmpty() bool
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||
)
|
||||
|
||||
func main() {
|
||||
set1 := set.NewSet(1, 2, 3)
|
||||
set2 := set.NewSet()
|
||||
|
||||
fmt.Println(set1.IsEmpty()) //false
|
||||
fmt.Println(set2.IsEmpty()) //true
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Union">Union</span>
|
||||
<p>Create a new set contain all element of set s and other</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s Set[T]) Union(other Set[T]) Set[T]
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||
)
|
||||
|
||||
func main() {
|
||||
set1 := set.NewSet(1, 2, 3)
|
||||
set2 := set.NewSet(2, 3, 4, 5)
|
||||
set3 := set1.Union(set2)
|
||||
|
||||
fmt.Println(set3.Values()) //1,2,3,4,5
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Intersection">Intersection</span>
|
||||
<p>Create a new set whose element both be contained in set s and other</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s Set[T]) Intersection(other Set[T]) Set[T]
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||
)
|
||||
|
||||
func main() {
|
||||
set1 := set.NewSet(1, 2, 3)
|
||||
set2 := set.NewSet(2, 3, 4, 5)
|
||||
set3 := set1.Intersection(set2)
|
||||
|
||||
fmt.Println(set3.Values()) //2,3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="SymmetricDifference">SymmetricDifference</span>
|
||||
<p>Create a new set whose element is in set1 or set2, but not in both set1 and set2</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s Set[T]) SymmetricDifference(other Set[T]) Set[T]
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||
)
|
||||
|
||||
func main() {
|
||||
set1 := set.NewSet(1, 2, 3)
|
||||
set2 := set.NewSet(2, 3, 4, 5)
|
||||
set3 := set1.SymmetricDifference(set2)
|
||||
|
||||
fmt.Println(set3.Values()) //1,4,5
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Minus">Minus</span>
|
||||
<p>Create an set of whose element in origin set but not in compared set</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s Set[T]) Minus(comparedSet Set[T]) Set[T]
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||
)
|
||||
|
||||
func main() {
|
||||
set1 := set.NewSet(1, 2, 3)
|
||||
set2 := set.NewSet(2, 3, 4, 5)
|
||||
set3 := set.NewSet(2, 3)
|
||||
|
||||
res1 := set1.Minus(set2)
|
||||
fmt.Println(res1.Values()) //1
|
||||
|
||||
res2 := set2.Minus(set3)
|
||||
fmt.Println(res2.Values()) //4,5
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
489
docs/datastructure/set_zh-CN.md
Normal file
489
docs/datastructure/set_zh-CN.md
Normal file
@@ -0,0 +1,489 @@
|
||||
# Set
|
||||
Set集合数据结构,类似列表。Set中元素不重复。
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 源码
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/datastructure/set/set.go](https://github.com/duke-git/lancet/blob/main/datastructure/set/set.go)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 用法
|
||||
```go
|
||||
import (
|
||||
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||
)
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 目录
|
||||
|
||||
- [NewSet](#NewSet)
|
||||
- [Values](#Values)
|
||||
- [Add](#Add)
|
||||
- [Delete](#Delete)
|
||||
- [Contain](#Contain)
|
||||
- [ContainAll](#ContainAll)
|
||||
- [Clone](#Clone)
|
||||
- [Size](#Size)
|
||||
- [Equal](#Equal)
|
||||
- [Iterate](#Iterate)
|
||||
- [IsEmpty](#IsEmpty)
|
||||
- [Union](#Union)
|
||||
- [Intersection](#Intersection)
|
||||
|
||||
- [SymmetricDifference](#SymmetricDifference)
|
||||
- [Minus](#Minus)
|
||||
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 文档
|
||||
|
||||
### <span id="NewSet">NewSet</span>
|
||||
<p>返回Set结构体对象</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
type Set[T comparable] map[T]bool
|
||||
func NewSet[T comparable](values ...T) Set[T]
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||
)
|
||||
|
||||
func main() {
|
||||
st := set.NewSet[int](1,2,2,3)
|
||||
fmt.Println(st.Values()) //1,2,3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Values">Values</span>
|
||||
<p>获取集合中所有元素的切片</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s Set[T]) Values() []T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||
)
|
||||
|
||||
func main() {
|
||||
st := set.NewSet[int](1,2,2,3)
|
||||
fmt.Println(st.Values()) //1,2,3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Add">Add</span>
|
||||
<p>向集合中添加元素</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s Set[T]) Add(values ...T)
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||
)
|
||||
|
||||
func main() {
|
||||
st := set.NewSet[int]()
|
||||
st.Add(1, 2, 3)
|
||||
|
||||
fmt.Println(st.Values()) //1,2,3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Delete">Delete</span>
|
||||
<p>删除集合中元素</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s Set[T]) Delete(values ...T)
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||
)
|
||||
|
||||
func main() {
|
||||
st := set.NewSet[int]()
|
||||
st.Add(1, 2, 3)
|
||||
|
||||
set.Delete(3)
|
||||
fmt.Println(st.Values()) //1,2
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Contain">Contain</span>
|
||||
<p>判断集合是否包含某个值</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s Set[T]) Contain(value T) bool
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||
)
|
||||
|
||||
func main() {
|
||||
st := set.NewSet[int]()
|
||||
st.Add(1, 2, 3)
|
||||
|
||||
fmt.Println(st.Contain(1)) //true
|
||||
fmt.Println(st.Contain(4)) //false
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="ContainAll">ContainAll</span>
|
||||
<p>判断集合是否包含另一个集合</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s Set[T]) ContainAll(other Set[T]) bool
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||
)
|
||||
|
||||
func main() {
|
||||
set1 := set.NewSet(1, 2, 3)
|
||||
set2 := set.NewSet(1, 2)
|
||||
set3 := set.NewSet(1, 2, 3, 4)
|
||||
|
||||
fmt.Println(set1.ContainAll(set2)) //true
|
||||
fmt.Println(set1.ContainAll(set3)) //false
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Size">Size</span>
|
||||
<p>获取集合中元素的个数</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s Set[T]) Size() int
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||
)
|
||||
|
||||
func main() {
|
||||
set1 := set.NewSet(1, 2, 3)
|
||||
|
||||
fmt.Println(set1.Size()) //3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Clone">Clone</span>
|
||||
<p>克隆一个集合</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s Set[T]) Clone() Set[T]
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||
)
|
||||
|
||||
func main() {
|
||||
set1 := set.NewSet(1, 2, 3)
|
||||
set2 := set1.Clone()
|
||||
|
||||
fmt.Println(set1.Size() == set2.Size()) //true
|
||||
fmt.Println(set1.ContainAll(set2)) //true
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Equal">Equal</span>
|
||||
<p>比较两个集合是否相等,包含相同元素为相等</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s Set[T]) Equal(other Set[T]) bool
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||
)
|
||||
|
||||
func main() {
|
||||
set1 := set.NewSet(1, 2, 3)
|
||||
set2 := set.NewSet(1, 2, 3)
|
||||
set3 := set.NewSet(1, 2, 3, 4)
|
||||
|
||||
fmt.Println(set1.Equal(set2)) //true
|
||||
fmt.Println(set1.Equal(set3)) //false
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Iterate">Iterate</span>
|
||||
<p>迭代结合,在每个元素上调用函数</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s Set[T]) Iterate(fn func(value T))
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||
)
|
||||
|
||||
func main() {
|
||||
set1 := set.NewSet(1, 2, 3)
|
||||
arr := []int{}
|
||||
set.Iterate(func(value int) {
|
||||
arr = append(arr, value)
|
||||
})
|
||||
|
||||
fmt.Println(arr) //1,2,3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="IsEmpty">IsEmpty</span>
|
||||
<p>判断集合是否为空</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s Set[T]) IsEmpty() bool
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||
)
|
||||
|
||||
func main() {
|
||||
set1 := set.NewSet(1, 2, 3)
|
||||
set2 := set.NewSet()
|
||||
|
||||
fmt.Println(set1.IsEmpty()) //false
|
||||
fmt.Println(set2.IsEmpty()) //true
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Union">Union</span>
|
||||
<p>求两个集合的并集</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s Set[T]) Union(other Set[T]) Set[T]
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||
)
|
||||
|
||||
func main() {
|
||||
set1 := set.NewSet(1, 2, 3)
|
||||
set2 := set.NewSet(2, 3, 4, 5)
|
||||
set3 := set1.Union(set2)
|
||||
|
||||
fmt.Println(set3.Values()) //1,2,3,4,5
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Intersection">Intersection</span>
|
||||
<p>求两个集合的交集</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s Set[T]) Intersection(other Set[T]) Set[T]
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||
)
|
||||
|
||||
func main() {
|
||||
set1 := set.NewSet(1, 2, 3)
|
||||
set2 := set.NewSet(2, 3, 4, 5)
|
||||
set3 := set1.Intersection(set2)
|
||||
|
||||
fmt.Println(set3.Values()) //2,3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="SymmetricDifference">SymmetricDifference</span>
|
||||
<p>返回一个集合,其中元素在第一个集合或第二个集合中,且不同时存在于两个集合中</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s Set[T]) SymmetricDifference(other Set[T]) Set[T]
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||
)
|
||||
|
||||
func main() {
|
||||
set1 := set.NewSet(1, 2, 3)
|
||||
set2 := set.NewSet(2, 3, 4, 5)
|
||||
set3 := set1.SymmetricDifference(set2)
|
||||
|
||||
fmt.Println(set3.Values()) //1,4,5
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Minus">Minus</span>
|
||||
<p>创建一个集合,其元素在原始集中但不在比较集中</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s Set[T]) Minus(comparedSet Set[T]) Set[T]
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||
)
|
||||
|
||||
func main() {
|
||||
set1 := set.NewSet(1, 2, 3)
|
||||
set2 := set.NewSet(2, 3, 4, 5)
|
||||
set3 := set.NewSet(2, 3)
|
||||
|
||||
res1 := set1.Minus(set2)
|
||||
fmt.Println(res1.Values()) //1
|
||||
|
||||
res2 := set2.Minus(set3)
|
||||
fmt.Println(res2.Values()) //4,5
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
611
docs/datastructure/stack.md
Normal file
611
docs/datastructure/stack.md
Normal file
@@ -0,0 +1,611 @@
|
||||
# Stack
|
||||
Stack is an abstract data type that serves as a collection of elements. Elements follow the LIFO principle. FIFO is last-in, first-out, meaning that the most recently produced items are recorded as sold first.
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Source
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/datastructure/stack/arraystack.go](https://github.com/duke-git/lancet/blob/main/datastructure/stack/arraystack.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/datastructure/stack/linkedstack.go](https://github.com/duke-git/lancet/blob/main/datastructure/stack/linkedstack.go)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Usage
|
||||
```go
|
||||
import (
|
||||
stack "github.com/duke-git/lancet/v2/datastructure/stack"
|
||||
)
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Index
|
||||
|
||||
### 1. ArrayStack
|
||||
|
||||
- [NewArrayStack](#NewArrayStack)
|
||||
- [Push](#ArrayStack_Push)
|
||||
- [Pop](#ArrayStack_Pop)
|
||||
- [Peak](#ArrayStack_Peak)
|
||||
- [Data](#ArrayStack_Data)
|
||||
- [Size](#ArrayStack_Size)
|
||||
- [IsEmpty](#ArrayStack_IsEmpty)
|
||||
- [Clear](#ArrayStack_Clear)
|
||||
|
||||
### 2. LinkedStack
|
||||
|
||||
- [NewLinkedStack](#NewLinkedStack)
|
||||
- [Push](#LinkedStack_Push)
|
||||
- [Pop](#LinkedStack_Pop)
|
||||
- [Peak](#LinkedStack_Peak)
|
||||
- [Data](#LinkedStack_Data)
|
||||
- [Size](#LinkedStack_Size)
|
||||
- [IsEmpty](#LinkedStack_IsEmpty)
|
||||
- [Clear](#LinkedStack_Clear)
|
||||
- [Print](#LinkedStack_Print)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Documentation
|
||||
|
||||
### 1. ArrayStack
|
||||
ArrayStack is a stack implemented by slice.
|
||||
|
||||
### <span id="NewArrayStack">NewArrayStack</span>
|
||||
<p>Return a empty ArrayStack pointer</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
type ArrayStack[T any] struct {
|
||||
data []T
|
||||
length int
|
||||
}
|
||||
func NewArrayStack[T any]() *ArrayStack[T]
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
stack "github.com/duke-git/lancet/v2/datastructure/stack"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sk := stack.NewArrayStack[int]()
|
||||
fmt.Println(sk)
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="ArrayStack_Push">Push</span>
|
||||
<p>Push element into array stack</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s *ArrayStack[T]) Push(value T)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
stack "github.com/duke-git/lancet/v2/datastructure/stack"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sk := stack.NewArrayStack[int]()
|
||||
sk.Push(1)
|
||||
sk.Push(2)
|
||||
sk.Push(3)
|
||||
|
||||
fmt.Println(sk.Data()) //[]int{3, 2, 1}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="ArrayStack_Pop">Pop</span>
|
||||
<p>Delete the top element of stack then return it, if stack is empty, return nil and error</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s *ArrayStack[T]) Pop() (*T, error)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
stack "github.com/duke-git/lancet/v2/datastructure/stack"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sk := stack.NewArrayStack[int]()
|
||||
sk.Push(1)
|
||||
sk.Push(2)
|
||||
sk.Push(3)
|
||||
|
||||
val, err := sk.Pop()
|
||||
fmt.Println(err) //nil
|
||||
fmt.Println(*val) //3
|
||||
|
||||
fmt.Println(sk.Data()) //[]int{2, 1}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="ArrayStack_Peak">Peak</span>
|
||||
<p>Return the top element of array stack</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s *ArrayStack[T]) Peak() (*T, error)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
stack "github.com/duke-git/lancet/v2/datastructure/stack"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sk := stack.NewArrayStack[int]()
|
||||
sk.Push(1)
|
||||
sk.Push(2)
|
||||
sk.Push(3)
|
||||
|
||||
val, err := sk.Peak()
|
||||
fmt.Println(err) //nil
|
||||
fmt.Println(*val) //3
|
||||
|
||||
fmt.Println(sk.Data()) //[]int{3, 2, 1}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="ArrayStack_Data">Data</span>
|
||||
<p>Return a slice of all data in array stack</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s *ArrayStack[T]) Data() []T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
stack "github.com/duke-git/lancet/v2/datastructure/stack"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sk := stack.NewArrayStack[int]()
|
||||
sk.Push(1)
|
||||
sk.Push(2)
|
||||
sk.Push(3)
|
||||
|
||||
fmt.Println(sk.Data()) //[]int{3, 2, 1}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="ArrayStack_Size">Size</span>
|
||||
<p>Return number of elements in array stack</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s *ArrayStack[T]) Size() int
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
stack "github.com/duke-git/lancet/v2/datastructure/stack"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sk := stack.NewArrayStack[int]()
|
||||
sk.Push(1)
|
||||
sk.Push(2)
|
||||
sk.Push(3)
|
||||
|
||||
fmt.Println(sk.Size()) //3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="ArrayStack_IsEmpty">IsEmpty</span>
|
||||
<p>Check if array stack is empty or not</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s *ArrayStack[T]) IsEmpty() bool
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
stack "github.com/duke-git/lancet/v2/datastructure/stack"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sk := stack.NewArrayStack[int]()
|
||||
fmt.Println(sk.IsEmpty()) //true
|
||||
|
||||
sk.Push(1)
|
||||
sk.Push(2)
|
||||
sk.Push(3)
|
||||
|
||||
fmt.Println(sk.IsEmpty()) //false
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="ArrayStack_Clear">Clear</span>
|
||||
<p>Clear all elments in array stack</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s *ArrayStack[T]) Clear()
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
stack "github.com/duke-git/lancet/v2/datastructure/stack"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sk := stack.NewArrayStack[int]()
|
||||
|
||||
sk.Push(1)
|
||||
sk.Push(2)
|
||||
sk.Push(3)
|
||||
|
||||
sk.Clear()
|
||||
|
||||
fmt.Println(sk.Data()) //[]int{}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 2. LinkedStack
|
||||
LinkedStack is a stack implemented by linked list.
|
||||
|
||||
### <span id="NewLinkedStack">NewLinkedStack</span>
|
||||
<p>Return a empty LinkedStack pointer</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
type StackNode[T any] struct {
|
||||
Value T
|
||||
Next *StackNode[T]
|
||||
}
|
||||
type LinkedStack[T any] struct {
|
||||
top *datastructure.StackNode[T]
|
||||
length int
|
||||
}
|
||||
func NewLinkedStack[T any]() *LinkedStack[T]
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
stack "github.com/duke-git/lancet/v2/datastructure/stack"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sk := stack.NewLinkedStack[int]()
|
||||
fmt.Println(sk)
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="LinkedStack_Push">Push</span>
|
||||
<p>Push element into linked stack</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s *LinkedStack[T]) Push(value T)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
stack "github.com/duke-git/lancet/v2/datastructure/stack"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sk := stack.NewLinkedStack[int]()
|
||||
sk.Push(1)
|
||||
sk.Push(2)
|
||||
sk.Push(3)
|
||||
|
||||
fmt.Println(sk.Data()) //[]int{3, 2, 1}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="LinkedStack_Pop">Pop</span>
|
||||
<p>Delete the top element of stack then return it, if stack is empty, return nil and error</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s *LinkedStack[T]) Pop() (*T, error)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
stack "github.com/duke-git/lancet/v2/datastructure/stack"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sk := stack.NewLinkedStack[int]()
|
||||
sk.Push(1)
|
||||
sk.Push(2)
|
||||
sk.Push(3)
|
||||
|
||||
val, err := sk.Pop()
|
||||
fmt.Println(err) //nil
|
||||
fmt.Println(*val) //3
|
||||
|
||||
fmt.Println(sk.Data()) //[]int{2, 1}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="LinkedStack_Peak">Peak</span>
|
||||
<p>Return the top element of linked stack</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s *LinkedStack[T]) Peak() (*T, error)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
stack "github.com/duke-git/lancet/v2/datastructure/stack"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sk := stack.NewLinkedStack[int]()
|
||||
sk.Push(1)
|
||||
sk.Push(2)
|
||||
sk.Push(3)
|
||||
|
||||
val, err := sk.Peak()
|
||||
fmt.Println(err) //nil
|
||||
fmt.Println(*val) //3
|
||||
|
||||
fmt.Println(sk.Data()) //[]int{3, 2, 1}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="LinkedStack_Data">Data</span>
|
||||
<p>Return a slice of all data in linked stack</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s *LinkedStack[T]) Data() []T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
stack "github.com/duke-git/lancet/v2/datastructure/stack"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sk := stack.NewLinkedStack[int]()
|
||||
sk.Push(1)
|
||||
sk.Push(2)
|
||||
sk.Push(3)
|
||||
|
||||
fmt.Println(sk.Data()) //[]int{3, 2, 1}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="LinkedStack_Size">Size</span>
|
||||
<p>Return number of elements in linked stack</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s *LinkedStack[T]) Size() int
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
stack "github.com/duke-git/lancet/v2/datastructure/stack"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sk := stack.NewLinkedStack[int]()
|
||||
sk.Push(1)
|
||||
sk.Push(2)
|
||||
sk.Push(3)
|
||||
|
||||
fmt.Println(sk.Size()) //3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="LinkedStack_IsEmpty">IsEmpty</span>
|
||||
<p>Check if linked stack is empty or not</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s *LinkedStack[T]) IsEmpty() bool
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
stack "github.com/duke-git/lancet/v2/datastructure/stack"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sk := stack.NewLinkedStack[int]()
|
||||
fmt.Println(sk.IsEmpty()) //true
|
||||
|
||||
sk.Push(1)
|
||||
sk.Push(2)
|
||||
sk.Push(3)
|
||||
|
||||
fmt.Println(sk.IsEmpty()) //false
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="LinkedStack_Clear">Clear</span>
|
||||
<p>Clear all elments in linked stack</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s *LinkedStack[T]) Clear()
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
stack "github.com/duke-git/lancet/v2/datastructure/stack"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sk := stack.NewLinkedStack[int]()
|
||||
|
||||
sk.Push(1)
|
||||
sk.Push(2)
|
||||
sk.Push(3)
|
||||
|
||||
sk.Clear()
|
||||
|
||||
fmt.Println(sk.Data()) //[]int{}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="LinkedStack_Print">Print</span>
|
||||
<p>Print the structure of a linked stack</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s *LinkedStack[T]) Print()
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
stack "github.com/duke-git/lancet/v2/datastructure/stack"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sk := stack.NewLinkedStack[int]()
|
||||
|
||||
sk.Push(1)
|
||||
sk.Push(2)
|
||||
sk.Push(3)
|
||||
|
||||
|
||||
sk.Print() //[ &{Value:3 Next:0xc000010260}, &{Value:2 Next:0xc000010250}, &{Value:1 Next:<nil>}, ]
|
||||
}
|
||||
```
|
||||
611
docs/datastructure/stack_zh-CN.md
Normal file
611
docs/datastructure/stack_zh-CN.md
Normal file
@@ -0,0 +1,611 @@
|
||||
# Stack
|
||||
栈数据结构,包括ArrayStack(数组栈)和LinkedStack(链表栈)。
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 源码
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/datastructure/stack/arraystack.go](https://github.com/duke-git/lancet/blob/main/datastructure/stack/arraystack.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/datastructure/stack/linkedstack.go](https://github.com/duke-git/lancet/blob/main/datastructure/stack/linkedstack.go)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 用法
|
||||
```go
|
||||
import (
|
||||
stack "github.com/duke-git/lancet/v2/datastructure/stack"
|
||||
)
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 目录
|
||||
|
||||
### 1. ArrayStack(数组栈)
|
||||
|
||||
- [NewArrayStack](#NewArrayStack)
|
||||
- [Push](#ArrayStack_Push)
|
||||
- [Pop](#ArrayStack_Pop)
|
||||
- [Peak](#ArrayStack_Peak)
|
||||
- [Data](#ArrayStack_Data)
|
||||
- [Size](#ArrayStack_Size)
|
||||
- [IsEmpty](#ArrayStack_IsEmpty)
|
||||
- [Clear](#ArrayStack_Clear)
|
||||
|
||||
### 2. LinkedStack(链表栈)
|
||||
|
||||
- [NewLinkedStack](#NewLinkedStack)
|
||||
- [Push](#LinkedStack_Push)
|
||||
- [Pop](#LinkedStack_Pop)
|
||||
- [Peak](#LinkedStack_Peak)
|
||||
- [Data](#LinkedStack_Data)
|
||||
- [Size](#LinkedStack_Size)
|
||||
- [IsEmpty](#LinkedStack_IsEmpty)
|
||||
- [Clear](#LinkedStack_Clear)
|
||||
- [Print](#LinkedStack_Print)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 文档
|
||||
|
||||
### 1. ArrayStack
|
||||
用切片实现栈结构
|
||||
|
||||
### <span id="NewArrayStack">NewArrayStack</span>
|
||||
<p>返回ArrayStack指针实例</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
type ArrayStack[T any] struct {
|
||||
data []T
|
||||
length int
|
||||
}
|
||||
func NewArrayStack[T any]() *ArrayStack[T]
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
stack "github.com/duke-git/lancet/v2/datastructure/stack"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sk := stack.NewArrayStack[int]()
|
||||
fmt.Println(sk)
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="ArrayStack_Push">Push</span>
|
||||
<p>将元素加入数组栈</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s *ArrayStack[T]) Push(value T)
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
stack "github.com/duke-git/lancet/v2/datastructure/stack"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sk := stack.NewArrayStack[int]()
|
||||
sk.Push(1)
|
||||
sk.Push(2)
|
||||
sk.Push(3)
|
||||
|
||||
fmt.Println(sk.Data()) //[]int{3, 2, 1}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="ArrayStack_Pop">Pop</span>
|
||||
<p>删除栈顶元素并返回该元素指针</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s *ArrayStack[T]) Pop() (*T, error)
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
stack "github.com/duke-git/lancet/v2/datastructure/stack"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sk := stack.NewArrayStack[int]()
|
||||
sk.Push(1)
|
||||
sk.Push(2)
|
||||
sk.Push(3)
|
||||
|
||||
val, err := sk.Pop()
|
||||
fmt.Println(err) //nil
|
||||
fmt.Println(*val) //3
|
||||
|
||||
fmt.Println(sk.Data()) //[]int{2, 1}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="ArrayStack_Peak">Peak</span>
|
||||
<p>返回栈顶元素指针</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s *ArrayStack[T]) Peak() (*T, error)
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
stack "github.com/duke-git/lancet/v2/datastructure/stack"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sk := stack.NewArrayStack[int]()
|
||||
sk.Push(1)
|
||||
sk.Push(2)
|
||||
sk.Push(3)
|
||||
|
||||
val, err := sk.Peak()
|
||||
fmt.Println(err) //nil
|
||||
fmt.Println(*val) //3
|
||||
|
||||
fmt.Println(sk.Data()) //[]int{3, 2, 1}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="ArrayStack_Data">Data</span>
|
||||
<p>返回栈中所有元素组成的切片</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s *ArrayStack[T]) Data() []T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
stack "github.com/duke-git/lancet/v2/datastructure/stack"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sk := stack.NewArrayStack[int]()
|
||||
sk.Push(1)
|
||||
sk.Push(2)
|
||||
sk.Push(3)
|
||||
|
||||
fmt.Println(sk.Data()) //[]int{3, 2, 1}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="ArrayStack_Size">Size</span>
|
||||
<p>返回栈中元素的数量</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s *ArrayStack[T]) Size() int
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
stack "github.com/duke-git/lancet/v2/datastructure/stack"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sk := stack.NewArrayStack[int]()
|
||||
sk.Push(1)
|
||||
sk.Push(2)
|
||||
sk.Push(3)
|
||||
|
||||
fmt.Println(sk.Size()) //3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="ArrayStack_IsEmpty">IsEmpty</span>
|
||||
<p>判断栈是否为空</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s *ArrayStack[T]) IsEmpty() bool
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
stack "github.com/duke-git/lancet/v2/datastructure/stack"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sk := stack.NewArrayStack[int]()
|
||||
fmt.Println(sk.IsEmpty()) //true
|
||||
|
||||
sk.Push(1)
|
||||
sk.Push(2)
|
||||
sk.Push(3)
|
||||
|
||||
fmt.Println(sk.IsEmpty()) //false
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="ArrayStack_Clear">Clear</span>
|
||||
<p>清空栈元素,使栈为空</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s *ArrayStack[T]) Clear()
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
stack "github.com/duke-git/lancet/v2/datastructure/stack"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sk := stack.NewArrayStack[int]()
|
||||
|
||||
sk.Push(1)
|
||||
sk.Push(2)
|
||||
sk.Push(3)
|
||||
|
||||
sk.Clear()
|
||||
|
||||
fmt.Println(sk.Data()) //[]int{}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 2. LinkedStack
|
||||
链表实现的栈结构。
|
||||
|
||||
### <span id="NewLinkedStack">NewLinkedStack</span>
|
||||
<p>返回LinkedStack指针实例</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
type StackNode[T any] struct {
|
||||
Value T
|
||||
Next *StackNode[T]
|
||||
}
|
||||
type LinkedStack[T any] struct {
|
||||
top *datastructure.StackNode[T]
|
||||
length int
|
||||
}
|
||||
func NewLinkedStack[T any]() *LinkedStack[T]
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
stack "github.com/duke-git/lancet/v2/datastructure/stack"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sk := stack.NewLinkedStack[int]()
|
||||
fmt.Println(sk)
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="LinkedStack_Push">Push</span>
|
||||
<p>将元素加入链表栈</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s *LinkedStack[T]) Push(value T)
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
stack "github.com/duke-git/lancet/v2/datastructure/stack"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sk := stack.NewLinkedStack[int]()
|
||||
sk.Push(1)
|
||||
sk.Push(2)
|
||||
sk.Push(3)
|
||||
|
||||
fmt.Println(sk.Data()) //[]int{3, 2, 1}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="LinkedStack_Pop">Pop</span>
|
||||
<p>删除栈顶元素并返回该元素指针</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s *LinkedStack[T]) Pop() (*T, error)
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
stack "github.com/duke-git/lancet/v2/datastructure/stack"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sk := stack.NewLinkedStack[int]()
|
||||
sk.Push(1)
|
||||
sk.Push(2)
|
||||
sk.Push(3)
|
||||
|
||||
val, err := sk.Pop()
|
||||
fmt.Println(err) //nil
|
||||
fmt.Println(*val) //3
|
||||
|
||||
fmt.Println(sk.Data()) //[]int{2, 1}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="LinkedStack_Peak">Peak</span>
|
||||
<p>返回栈顶元素指针</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s *LinkedStack[T]) Peak() (*T, error)
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
stack "github.com/duke-git/lancet/v2/datastructure/stack"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sk := stack.NewLinkedStack[int]()
|
||||
sk.Push(1)
|
||||
sk.Push(2)
|
||||
sk.Push(3)
|
||||
|
||||
val, err := sk.Peak()
|
||||
fmt.Println(err) //nil
|
||||
fmt.Println(*val) //3
|
||||
|
||||
fmt.Println(sk.Data()) //[]int{3, 2, 1}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="LinkedStack_Data">Data</span>
|
||||
<p>返回栈中所有元素组成的切片</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s *LinkedStack[T]) Data() []T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
stack "github.com/duke-git/lancet/v2/datastructure/stack"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sk := stack.NewLinkedStack[int]()
|
||||
sk.Push(1)
|
||||
sk.Push(2)
|
||||
sk.Push(3)
|
||||
|
||||
fmt.Println(sk.Data()) //[]int{3, 2, 1}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="LinkedStack_Size">Size</span>
|
||||
<p>返回栈中元素的数量</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s *LinkedStack[T]) Size() int
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
stack "github.com/duke-git/lancet/v2/datastructure/stack"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sk := stack.NewLinkedStack[int]()
|
||||
sk.Push(1)
|
||||
sk.Push(2)
|
||||
sk.Push(3)
|
||||
|
||||
fmt.Println(sk.Size()) //3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="LinkedStack_IsEmpty">IsEmpty</span>
|
||||
<p>判断栈是否为空</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s *LinkedStack[T]) IsEmpty() bool
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
stack "github.com/duke-git/lancet/v2/datastructure/stack"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sk := stack.NewLinkedStack[int]()
|
||||
fmt.Println(sk.IsEmpty()) //true
|
||||
|
||||
sk.Push(1)
|
||||
sk.Push(2)
|
||||
sk.Push(3)
|
||||
|
||||
fmt.Println(sk.IsEmpty()) //false
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="LinkedStack_Clear">Clear</span>
|
||||
<p>清空栈元素,使栈为空</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s *LinkedStack[T]) Clear()
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
stack "github.com/duke-git/lancet/v2/datastructure/stack"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sk := stack.NewLinkedStack[int]()
|
||||
|
||||
sk.Push(1)
|
||||
sk.Push(2)
|
||||
sk.Push(3)
|
||||
|
||||
sk.Clear()
|
||||
|
||||
fmt.Println(sk.Data()) //[]int{}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="LinkedStack_Print">Print</span>
|
||||
<p>打印链表栈结构</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s *LinkedStack[T]) Print()
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
stack "github.com/duke-git/lancet/v2/datastructure/stack"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sk := stack.NewLinkedStack[int]()
|
||||
|
||||
sk.Push(1)
|
||||
sk.Push(2)
|
||||
sk.Push(3)
|
||||
|
||||
|
||||
sk.Print() //[ &{Value:3 Next:0xc000010260}, &{Value:2 Next:0xc000010250}, &{Value:1 Next:<nil>}, ]
|
||||
}
|
||||
```
|
||||
527
docs/datastructure/tree.md
Normal file
527
docs/datastructure/tree.md
Normal file
@@ -0,0 +1,527 @@
|
||||
# Tree
|
||||
Tree is a collection of tree nodes. Each tree node has a value, a left pointer point to left node and a right pointer point to right node.
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Source
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/datastructure/tree/bstree.go](https://github.com/duke-git/lancet/blob/main/datastructure/tree/bstree.go)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Usage
|
||||
```go
|
||||
import (
|
||||
tree "github.com/duke-git/lancet/v2/datastructure/tree"
|
||||
)
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Index
|
||||
|
||||
### 1. BSTree
|
||||
|
||||
- [NewBSTree](#NewBSTree)
|
||||
- [Insert](#BSTree_Insert)
|
||||
- [Delete](#BSTree_Delete)
|
||||
- [PreOrderTraverse](#BSTree_PreOrderTraverse)
|
||||
- [InOrderTraverse](#BSTree_InOrderTraverse)
|
||||
- [PostOrderTraverse](#BSTree_PostOrderTraverse)
|
||||
|
||||
- [LevelOrderTraverse](#BSTree_LevelOrderTraverse)
|
||||
- [Depth](#BSTree_Depth)
|
||||
- [HasSubTree](#BSTree_HasSubTree)
|
||||
- [Print](#BSTree_Print)
|
||||
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Documentation
|
||||
|
||||
## 1. BSTree
|
||||
BSTree is a binary search tree data structure in which each node has at two children, which are referred to as the left child and the right child. In BSTree: leftNode < rootNode < rightNode. Type T should implements Compare function in lancetconstraints.Comparator interface.
|
||||
|
||||
### <span id="NewBSTree">NewBSTree</span>
|
||||
<p>Make a BSTree pointer instance</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func NewBSTree[T any](rootData T, comparator lancetconstraints.Comparator) *BSTree[T]
|
||||
|
||||
type BSTree[T any] struct {
|
||||
root *datastructure.TreeNode[T]
|
||||
comparator lancetconstraints.Comparator
|
||||
}
|
||||
|
||||
type TreeNode[T any] struct {
|
||||
Value T
|
||||
Left *TreeNode[T]
|
||||
Right *TreeNode[T]
|
||||
}
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
tree "github.com/duke-git/lancet/v2/datastructure/tree"
|
||||
)
|
||||
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func main() {
|
||||
bstree := tree.NewBSTree(6, &intComparator{})
|
||||
fmt.Println(bstree) //
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="BSTree_Insert">Insert</span>
|
||||
<p>Insert value into binary search tree</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (t *BSTree[T]) Insert(data T)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
tree "github.com/duke-git/lancet/v2/datastructure/tree"
|
||||
)
|
||||
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func main() {
|
||||
bstree := tree.NewBSTree(6, &intComparator{})
|
||||
bstree.Insert(7)
|
||||
bstree.Insert(5)
|
||||
bstree.Insert(2)
|
||||
bstree.Insert(4)
|
||||
|
||||
fmt.Println(bstree.PreOrderTraverse()) //6, 5, 2, 4, 7
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="BSTree_Delete">Delete</span>
|
||||
<p>Delete value of binary search tree</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (t *BSTree[T]) Delete(data T)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
tree "github.com/duke-git/lancet/v2/datastructure/tree"
|
||||
)
|
||||
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func main() {
|
||||
bstree := tree.NewBSTree(6, &intComparator{})
|
||||
bstree.Insert(7)
|
||||
bstree.Insert(5)
|
||||
bstree.Insert(2)
|
||||
bstree.Insert(4)
|
||||
|
||||
bstree.Delete(4)
|
||||
|
||||
fmt.Println(bstree.PreOrderTraverse()) //2, 5, 6, 7
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="BSTree_PreOrderTraverse">PreOrderTraverse</span>
|
||||
<p>Traverse tree nodes in pre order</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (t *BSTree[T]) PreOrderTraverse() []T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
tree "github.com/duke-git/lancet/v2/datastructure/tree"
|
||||
)
|
||||
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func main() {
|
||||
bstree := tree.NewBSTree(6, &intComparator{})
|
||||
bstree.Insert(7)
|
||||
bstree.Insert(5)
|
||||
bstree.Insert(2)
|
||||
bstree.Insert(4)
|
||||
|
||||
fmt.Println(bstree.PreOrderTraverse()) //6, 5, 2, 4, 7
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="BSTree_InOrderTraverse">InOrderTraverse</span>
|
||||
<p>Traverse tree nodes in middle order</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (t *BSTree[T]) InOrderTraverse() []T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
tree "github.com/duke-git/lancet/v2/datastructure/tree"
|
||||
)
|
||||
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func main() {
|
||||
bstree := tree.NewBSTree(6, &intComparator{})
|
||||
bstree.Insert(7)
|
||||
bstree.Insert(5)
|
||||
bstree.Insert(2)
|
||||
bstree.Insert(4)
|
||||
|
||||
fmt.Println(bstree.InOrderTraverse()) //2, 4, 5, 6, 7
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="BSTree_PostOrderTraverse">PostOrderTraverse</span>
|
||||
<p>Traverse tree nodes in post order</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (t *BSTree[T]) PostOrderTraverse() []T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
tree "github.com/duke-git/lancet/v2/datastructure/tree"
|
||||
)
|
||||
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func main() {
|
||||
bstree := tree.NewBSTree(6, &intComparator{})
|
||||
bstree.Insert(7)
|
||||
bstree.Insert(5)
|
||||
bstree.Insert(2)
|
||||
bstree.Insert(4)
|
||||
|
||||
fmt.Println(bstree.PostOrderTraverse()) //5, 2, 4, 7, 6
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="BSTree_LevelOrderTraverse">LevelOrderTraverse</span>
|
||||
<p>Traverse tree nodes in node level order</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (t *BSTree[T]) LevelOrderTraverse() []T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
tree "github.com/duke-git/lancet/v2/datastructure/tree"
|
||||
)
|
||||
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func main() {
|
||||
bstree := tree.NewBSTree(6, &intComparator{})
|
||||
bstree.Insert(7)
|
||||
bstree.Insert(5)
|
||||
bstree.Insert(2)
|
||||
bstree.Insert(4)
|
||||
|
||||
fmt.Println(bstree.LevelOrderTraverse()) //6, 5, 7, 2, 4
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="BSTree_Depth">Depth</span>
|
||||
<p>Get the depth of a binary saerch tree</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (t *BSTree[T]) Depth() int
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
tree "github.com/duke-git/lancet/v2/datastructure/tree"
|
||||
)
|
||||
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func main() {
|
||||
bstree := tree.NewBSTree(6, &intComparator{})
|
||||
bstree.Insert(7)
|
||||
bstree.Insert(5)
|
||||
bstree.Insert(2)
|
||||
bstree.Insert(4)
|
||||
|
||||
fmt.Println(bstree.Depth()) //4
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="BSTree_HasSubTree">HasSubTree</span>
|
||||
<p>Check if the given tree is sub tree of origin tree or not</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (t *BSTree[T]) HasSubTree(subTree *BSTree[T]) bool
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
tree "github.com/duke-git/lancet/v2/datastructure/tree"
|
||||
)
|
||||
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func main() {
|
||||
superTree := tree.NewBSTree(8, &intComparator{})
|
||||
superTree.Insert(4)
|
||||
superTree.Insert(5)
|
||||
superTree.Insert(6)
|
||||
superTree.Insert(9)
|
||||
superTree.Insert(4)
|
||||
|
||||
subTree := tree.NewBSTree(5, &intComparator{})
|
||||
subTree.Insert(4)
|
||||
subTree.Insert(6)
|
||||
|
||||
fmt.Println(superTree.HasSubTree(subTree)) //true
|
||||
fmt.Println(subTree.HasSubTree(superTree)) //false
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="BSTree_Print">Print</span>
|
||||
<p>Print the structure of binary saerch tree</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (t *BSTree[T]) Print()
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
tree "github.com/duke-git/lancet/v2/datastructure/tree"
|
||||
)
|
||||
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func main() {
|
||||
bstree := tree.NewBSTree(6, &intComparator{})
|
||||
bstree.Insert(7)
|
||||
bstree.Insert(5)
|
||||
bstree.Insert(2)
|
||||
bstree.Insert(4)
|
||||
|
||||
fmt.Println(bstree.Print())
|
||||
// 6
|
||||
// / \
|
||||
// / \
|
||||
// / \
|
||||
// / \
|
||||
// 5 7
|
||||
// /
|
||||
// /
|
||||
// 2
|
||||
// \
|
||||
// 4
|
||||
}
|
||||
```
|
||||
527
docs/datastructure/tree_zh-CN.md
Normal file
527
docs/datastructure/tree_zh-CN.md
Normal file
@@ -0,0 +1,527 @@
|
||||
# Tree
|
||||
树是树节点的集合。 每个树节点都有一个值,一个指向左节点的左指针和一个指向右节点的右指针。
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 源码
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/datastructure/tree/bstree.go](https://github.com/duke-git/lancet/blob/main/datastructure/tree/bstree.go)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 用法
|
||||
```go
|
||||
import (
|
||||
tree "github.com/duke-git/lancet/v2/datastructure/tree"
|
||||
)
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 目录
|
||||
|
||||
### 1. BSTree
|
||||
|
||||
- [NewBSTree](#NewBSTree)
|
||||
- [Insert](#BSTree_Insert)
|
||||
- [Delete](#BSTree_Delete)
|
||||
- [PreOrderTraverse](#BSTree_PreOrderTraverse)
|
||||
- [InOrderTraverse](#BSTree_InOrderTraverse)
|
||||
- [PostOrderTraverse](#BSTree_PostOrderTraverse)
|
||||
|
||||
- [LevelOrderTraverse](#BSTree_LevelOrderTraverse)
|
||||
- [Depth](#BSTree_Depth)
|
||||
- [HasSubTree](#BSTree_HasSubTree)
|
||||
- [Print](#BSTree_Print)
|
||||
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 文档
|
||||
|
||||
## 1. BSTree
|
||||
BSTree是一种二叉搜索树数据结构,其中每个节点有两个孩子,分别称为左孩子和右孩子。 在 BSTree 中:leftNode < rootNode < rightNode。 T类型应该实现lancetconstraints.Comparator。
|
||||
|
||||
### <span id="NewBSTree">NewBSTree</span>
|
||||
<p>返回BSTree指针实例</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func NewBSTree[T any](rootData T, comparator lancetconstraints.Comparator) *BSTree[T]
|
||||
|
||||
type BSTree[T any] struct {
|
||||
root *datastructure.TreeNode[T]
|
||||
comparator lancetconstraints.Comparator
|
||||
}
|
||||
|
||||
type TreeNode[T any] struct {
|
||||
Value T
|
||||
Left *TreeNode[T]
|
||||
Right *TreeNode[T]
|
||||
}
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
tree "github.com/duke-git/lancet/v2/datastructure/tree"
|
||||
)
|
||||
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func main() {
|
||||
bstree := tree.NewBSTree(6, &intComparator{})
|
||||
fmt.Println(bstree) //
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="BSTree_Insert">Insert</span>
|
||||
<p>将值插入二叉搜索树</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (t *BSTree[T]) Insert(data T)
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
tree "github.com/duke-git/lancet/v2/datastructure/tree"
|
||||
)
|
||||
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func main() {
|
||||
bstree := tree.NewBSTree(6, &intComparator{})
|
||||
bstree.Insert(7)
|
||||
bstree.Insert(5)
|
||||
bstree.Insert(2)
|
||||
bstree.Insert(4)
|
||||
|
||||
fmt.Println(bstree.PreOrderTraverse()) //6, 5, 2, 4, 7
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="BSTree_Delete">Delete</span>
|
||||
<p>删除插入二叉搜索树中指定的值</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (t *BSTree[T]) Delete(data T)
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
tree "github.com/duke-git/lancet/v2/datastructure/tree"
|
||||
)
|
||||
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func main() {
|
||||
bstree := tree.NewBSTree(6, &intComparator{})
|
||||
bstree.Insert(7)
|
||||
bstree.Insert(5)
|
||||
bstree.Insert(2)
|
||||
bstree.Insert(4)
|
||||
|
||||
bstree.Delete(4)
|
||||
|
||||
fmt.Println(bstree.PreOrderTraverse()) //2, 5, 6, 7
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="BSTree_PreOrderTraverse">PreOrderTraverse</span>
|
||||
<p>按前序遍历树节点</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (t *BSTree[T]) PreOrderTraverse() []T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
tree "github.com/duke-git/lancet/v2/datastructure/tree"
|
||||
)
|
||||
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func main() {
|
||||
bstree := tree.NewBSTree(6, &intComparator{})
|
||||
bstree.Insert(7)
|
||||
bstree.Insert(5)
|
||||
bstree.Insert(2)
|
||||
bstree.Insert(4)
|
||||
|
||||
fmt.Println(bstree.PreOrderTraverse()) //6, 5, 2, 4, 7
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="BSTree_InOrderTraverse">InOrderTraverse</span>
|
||||
<p>按中序遍历树节点</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (t *BSTree[T]) InOrderTraverse() []T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
tree "github.com/duke-git/lancet/v2/datastructure/tree"
|
||||
)
|
||||
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func main() {
|
||||
bstree := tree.NewBSTree(6, &intComparator{})
|
||||
bstree.Insert(7)
|
||||
bstree.Insert(5)
|
||||
bstree.Insert(2)
|
||||
bstree.Insert(4)
|
||||
|
||||
fmt.Println(bstree.InOrderTraverse()) //2, 4, 5, 6, 7
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="BSTree_PostOrderTraverse">PostOrderTraverse</span>
|
||||
<p>按后序遍历树节点</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (t *BSTree[T]) PostOrderTraverse() []T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
tree "github.com/duke-git/lancet/v2/datastructure/tree"
|
||||
)
|
||||
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func main() {
|
||||
bstree := tree.NewBSTree(6, &intComparator{})
|
||||
bstree.Insert(7)
|
||||
bstree.Insert(5)
|
||||
bstree.Insert(2)
|
||||
bstree.Insert(4)
|
||||
|
||||
fmt.Println(bstree.PostOrderTraverse()) //5, 2, 4, 7, 6
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="BSTree_LevelOrderTraverse">LevelOrderTraverse</span>
|
||||
<p>按节点层次遍历树节点</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (t *BSTree[T]) LevelOrderTraverse() []T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
tree "github.com/duke-git/lancet/v2/datastructure/tree"
|
||||
)
|
||||
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func main() {
|
||||
bstree := tree.NewBSTree(6, &intComparator{})
|
||||
bstree.Insert(7)
|
||||
bstree.Insert(5)
|
||||
bstree.Insert(2)
|
||||
bstree.Insert(4)
|
||||
|
||||
fmt.Println(bstree.LevelOrderTraverse()) //6, 5, 7, 2, 4
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="BSTree_Depth">Depth</span>
|
||||
<p>获取树的深度</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (t *BSTree[T]) Depth() int
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
tree "github.com/duke-git/lancet/v2/datastructure/tree"
|
||||
)
|
||||
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func main() {
|
||||
bstree := tree.NewBSTree(6, &intComparator{})
|
||||
bstree.Insert(7)
|
||||
bstree.Insert(5)
|
||||
bstree.Insert(2)
|
||||
bstree.Insert(4)
|
||||
|
||||
fmt.Println(bstree.Depth()) //4
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="BSTree_HasSubTree">HasSubTree</span>
|
||||
<p>判断给定树是否是子树</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (t *BSTree[T]) HasSubTree(subTree *BSTree[T]) bool
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
tree "github.com/duke-git/lancet/v2/datastructure/tree"
|
||||
)
|
||||
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func main() {
|
||||
superTree := tree.NewBSTree(8, &intComparator{})
|
||||
superTree.Insert(4)
|
||||
superTree.Insert(5)
|
||||
superTree.Insert(6)
|
||||
superTree.Insert(9)
|
||||
superTree.Insert(4)
|
||||
|
||||
subTree := tree.NewBSTree(5, &intComparator{})
|
||||
subTree.Insert(4)
|
||||
subTree.Insert(6)
|
||||
|
||||
fmt.Println(superTree.HasSubTree(subTree)) //true
|
||||
fmt.Println(subTree.HasSubTree(superTree)) //false
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="BSTree_Print">Print</span>
|
||||
<p>打印树结构</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (t *BSTree[T]) Print()
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
tree "github.com/duke-git/lancet/v2/datastructure/tree"
|
||||
)
|
||||
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func main() {
|
||||
bstree := tree.NewBSTree(6, &intComparator{})
|
||||
bstree.Insert(7)
|
||||
bstree.Insert(5)
|
||||
bstree.Insert(2)
|
||||
bstree.Insert(4)
|
||||
|
||||
fmt.Println(bstree.Print())
|
||||
// 6
|
||||
// / \
|
||||
// / \
|
||||
// / \
|
||||
// / \
|
||||
// 5 7
|
||||
// /
|
||||
// /
|
||||
// 2
|
||||
// \
|
||||
// 4
|
||||
}
|
||||
```
|
||||
@@ -25,7 +25,9 @@ import (
|
||||
- [Fibonacci](#Fibonacci)
|
||||
- [Factorial](#Factorial)
|
||||
- [Max](#Max)
|
||||
- [MaxBy](#MaxBy)
|
||||
- [Min](#Min)
|
||||
- [MinBy](#MaxBy)
|
||||
|
||||
- [Percent](#Percent)
|
||||
- [RoundToFloat](#RoundToFloat)
|
||||
@@ -177,6 +179,45 @@ func main() {
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="MaxBy">MaxBy</span>
|
||||
<p>Return the maximum value of a slice using the given comparator function.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func MaxBy[T any](slice []T, comparator func(T, T) bool) T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
res1 := mathutil.MaxBy([]string{"a", "ab", "abc"}, func(v1, v2 string) bool {
|
||||
return len(v1) > len(v2)
|
||||
})
|
||||
fmt.Println(res1) //abc
|
||||
|
||||
res2 := mathutil.MaxBy([]string{"abd", "abc", "ab"}, func(v1, v2 string) bool {
|
||||
return len(v1) > len(v2)
|
||||
})
|
||||
fmt.Println(res2) //abd
|
||||
|
||||
res3 := mathutil.MaxBy([]string{}, func(v1, v2 string) bool {
|
||||
return len(v1) > len(v2)
|
||||
})
|
||||
fmt.Println(res3) //“”
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Min">Min</span>
|
||||
<p>Return min value of numbers.</p>
|
||||
|
||||
@@ -204,6 +245,45 @@ func main() {
|
||||
|
||||
|
||||
|
||||
### <span id="MinBy">MinBy</span>
|
||||
<p>Return the minimum value of a slice using the given comparator function.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func MinBy[T any](slice []T, comparator func(T, T) bool) T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
res1 := mathutil.MinBy([]string{"a", "ab", "abc"}, func(v1, v2 string) bool {
|
||||
return len(v1) < len(v2)
|
||||
})
|
||||
fmt.Println(res1) //a
|
||||
|
||||
res2 := mathutil.MinBy([]string{"ab", "ac", "abc"}, func(v1, v2 string) bool {
|
||||
return len(v1) < len(v2)
|
||||
})
|
||||
fmt.Println(res2) //ab
|
||||
|
||||
res3 := mathutil.MinBy([]string{}, func(v1, v2 string) bool {
|
||||
return len(v1) < len(v2)
|
||||
})
|
||||
fmt.Println(res3) //“”
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Percent">Percent</span>
|
||||
<p>calculate the percentage of val to total, retain n decimal places.</p>
|
||||
|
||||
|
||||
@@ -25,7 +25,9 @@ import (
|
||||
- [Fibonacci](#Fibonacci)
|
||||
- [Factorial](#Factorial)
|
||||
- [Max](#Max)
|
||||
- [MaxBy](#MaxBy)
|
||||
- [Min](#Min)
|
||||
- [MinBy](#MaxBy)
|
||||
|
||||
- [Percent](#Percent)
|
||||
- [RoundToFloat](#RoundToFloat)
|
||||
@@ -174,6 +176,45 @@ func main() {
|
||||
|
||||
|
||||
|
||||
### <span id="MaxBy">MaxBy</span>
|
||||
<p>使用给定的比较器函数返回切片的最大值</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func MaxBy[T any](slice []T, comparator func(T, T) bool) T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
res1 := mathutil.MaxBy([]string{"a", "ab", "abc"}, func(v1, v2 string) bool {
|
||||
return len(v1) > len(v2)
|
||||
})
|
||||
fmt.Println(res1) //abc
|
||||
|
||||
res2 := mathutil.MaxBy([]string{"abd", "abc", "ab"}, func(v1, v2 string) bool {
|
||||
return len(v1) > len(v2)
|
||||
})
|
||||
fmt.Println(res2) //abd
|
||||
|
||||
res3 := mathutil.MaxBy([]string{}, func(v1, v2 string) bool {
|
||||
return len(v1) > len(v2)
|
||||
})
|
||||
fmt.Println(res3) //“”
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Min">Min</span>
|
||||
<p>返回参数中的最小数</p>
|
||||
|
||||
@@ -201,6 +242,45 @@ func main() {
|
||||
|
||||
|
||||
|
||||
### <span id="MinBy">MinBy</span>
|
||||
<p>使用给定的比较器函数返回切片的最小值</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func MinBy[T any](slice []T, comparator func(T, T) bool) T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
res1 := mathutil.MinBy([]string{"a", "ab", "abc"}, func(v1, v2 string) bool {
|
||||
return len(v1) < len(v2)
|
||||
})
|
||||
fmt.Println(res1) //a
|
||||
|
||||
res2 := mathutil.MinBy([]string{"ab", "ac", "abc"}, func(v1, v2 string) bool {
|
||||
return len(v1) < len(v2)
|
||||
})
|
||||
fmt.Println(res2) //ab
|
||||
|
||||
res3 := mathutil.MinBy([]string{}, func(v1, v2 string) bool {
|
||||
return len(v1) < len(v2)
|
||||
})
|
||||
fmt.Println(res3) //“”
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Percent">Percent</span>
|
||||
<p>计算百分比,保留n位小数</p>
|
||||
|
||||
|
||||
@@ -44,6 +44,8 @@ import (
|
||||
- [InterfaceSlice](#InterfaceSlice)
|
||||
- [Intersection](#Intersection)
|
||||
- [InsertAt](#InsertAt)
|
||||
- [IndexOf](#IndexOf)
|
||||
- [LastIndexOf](#LastIndexOf)
|
||||
- [Map](#Map)
|
||||
- [Reverse](#Reverse)
|
||||
- [Reduce](#Reduce)
|
||||
@@ -248,7 +250,7 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func DifferenceBy[T any](slice []T, comparedSlice []T, iteratee func(index int, t T) T) []T
|
||||
func DifferenceBy[T any](slice []T, comparedSlice []T, iteratee func(index int, item T) T) []T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -365,7 +367,7 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Every[T any](slice []T, predicate func(index int, t T) bool) bool
|
||||
func Every[T any](slice []T, predicate func(index int, item T) bool) bool
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -395,7 +397,7 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Filter[T any](slice []T, predicate func(index int, t T) bool) []T
|
||||
func Filter[T any](slice []T, predicate func(index int, item T) bool) []T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -424,7 +426,7 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Find[T any](slice []T, predicate func(index int, t T) bool) (*T, bool)
|
||||
func Find[T any](slice []T, predicate func(index int, item T) bool) (*T, bool)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -455,7 +457,7 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func FindLast[T any](slice []T, predicate func(index int, t T) bool) (*T, bool)
|
||||
func FindLast[T any](slice []T, predicate func(index int, item T) bool) (*T, bool)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -512,7 +514,7 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func ForEach[T any](slice []T, iteratee func(index int, t T))
|
||||
func ForEach[T any](slice []T, iteratee func(index int, item T))
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -541,7 +543,7 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func GroupBy[T any](slice []T, groupFn func(index int, t T) bool) ([]T, []T)
|
||||
func GroupBy[T any](slice []T, groupFn func(index int, item T) bool) ([]T, []T)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -704,13 +706,70 @@ func main() {
|
||||
|
||||
|
||||
|
||||
### <span id="IndexOf">IndexOf</span>
|
||||
<p>Returns the index at which the first occurrence of a value is found in a slice or return -1 if the value cannot be found.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func IndexOf[T any](slice []T, value T) int
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
arr := []string{"a", "a", "b", "c"}
|
||||
res1 := slice.IndexOf(arr, "a")
|
||||
fmt.Println(res1) //0
|
||||
|
||||
res2 := slice.IndexOf(arr, "d")
|
||||
fmt.Println(res2) //-1
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="LastIndexOf">LastIndexOf</span>
|
||||
<p>Returns the index at which the last occurrence of a value is found in a slice or return -1 if the value cannot be found.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func LastIndexOf[T any](slice []T, value T) int
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
arr := []string{"a", "a", "b", "c"}
|
||||
res1 := slice.LastIndexOf(arr, "a")
|
||||
fmt.Println(res1) //1
|
||||
|
||||
res2 := slice.LastIndexOf(arr, "d")
|
||||
fmt.Println(res2) //-1
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Map">Map</span>
|
||||
<p>Creates an slice of values by running each element in slice thru function.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Map[T any, U any](slice []T, iteratee func(index int, t T) U) []U
|
||||
func Map[T any, U any](slice []T, iteratee func(index int, item T) U) []U
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -764,7 +823,7 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Reduce[T any](slice []T, iteratee func(index int, t1, t2 T) T, initial T) T
|
||||
func Reduce[T any](slice []T, iteratee func(index int, item1, item2 T) T, initial T) T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -861,7 +920,7 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Some[T any](slice []T, predicate func(index int, t T) bool) bool
|
||||
func Some[T any](slice []T, predicate func(index int, item T) bool) bool
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
|
||||
@@ -44,6 +44,8 @@ import (
|
||||
- [InterfaceSlice](#InterfaceSlice)
|
||||
- [Intersection](#Intersection)
|
||||
- [InsertAt](#InsertAt)
|
||||
- [IndexOf](#IndexOf)
|
||||
- [LastIndexOf](#LastIndexOf)
|
||||
- [Map](#Map)
|
||||
- [Reverse](#Reverse)
|
||||
- [Reduce](#Reduce)
|
||||
@@ -248,7 +250,7 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func DifferenceBy[T any](slice []T, comparedSlice []T, iteratee func(index int, t T) T) []T
|
||||
func DifferenceBy[T any](slice []T, comparedSlice []T, iteratee func(index int, item T) T) []T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -367,7 +369,7 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Every[T any](slice []T, predicate func(index int, t T) bool) bool
|
||||
func Every[T any](slice []T, predicate func(index int, item T) bool) bool
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -392,12 +394,12 @@ func main() {
|
||||
|
||||
|
||||
### <span id="Filter">Filter</span>
|
||||
<p>返回与函数匹配的所有元素。 函数签名应该是 func(index int, value any) bool</p>
|
||||
<p>返回切片中通过predicate函数真值测试的所有元素</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Filter[T any](slice []T, predicate func(index int, t T) bool) []T
|
||||
func Filter[T any](slice []T, predicate func(index int, item T) bool) []T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -421,12 +423,12 @@ func main() {
|
||||
|
||||
|
||||
### <span id="Find">Find</span>
|
||||
<p>遍历slice的元素,返回第一个通过function真值测试的元素</p>
|
||||
<p>遍历切片的元素,返回第一个通过predicate函数真值测试的元素</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Find[T any](slice []T, predicate func(index int, t T) bool) (*T, bool)
|
||||
func Find[T any](slice []T, predicate func(index int, item T) bool) (*T, bool)
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -452,12 +454,12 @@ func main() {
|
||||
|
||||
|
||||
### <span id="FindLast">FindLast</span>
|
||||
<p>从头到尾遍历 slice 的元素,返回最后一个通过函数真值测试的元素。</p>
|
||||
<p>从头到尾遍历slice的元素,返回最后一个通过predicate函数真值测试的元素。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func FindLast[T any](slice []T, predicate func(index int, t T) bool) (*T, bool)
|
||||
func FindLast[T any](slice []T, predicate func(index int, item T) bool) (*T, bool)
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -509,12 +511,12 @@ func main() {
|
||||
|
||||
|
||||
### <span id="ForEach">ForEach</span>
|
||||
<p>遍历slice的元素并为每个元素调用函数</p>
|
||||
<p>遍历切片的元素并为每个元素调用iteratee函数</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ForEach[T any](slice []T, iteratee func(index int, t T))
|
||||
func ForEach[T any](slice []T, iteratee func(index int, item T))
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -543,7 +545,7 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func GroupBy[T any](slice []T, groupFn func(index int, t T) bool) ([]T, []T)
|
||||
func GroupBy[T any](slice []T, groupFn func(index int, item T) bool) ([]T, []T)
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -704,13 +706,69 @@ func main() {
|
||||
|
||||
|
||||
|
||||
### <span id="IndexOf">IndexOf</span>
|
||||
<p>返回在切片中找到值的第一个匹配项的索引,如果找不到值,则返回-1</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func IndexOf[T any](slice []T, value T) int
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
arr := []string{"a", "a", "b", "c"}
|
||||
res1 := slice.IndexOf(arr, "a")
|
||||
fmt.Println(res1) //0
|
||||
|
||||
res2 := slice.IndexOf(arr, "d")
|
||||
fmt.Println(res2) //-1
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="LastIndexOf">LastIndexOf</span>
|
||||
<p>返回在切片中找到最后一个值的索引,如果找不到该值,则返回-1</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func LastIndexOf[T any](slice []T, value T) int
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
arr := []string{"a", "a", "b", "c"}
|
||||
res1 := slice.LastIndexOf(arr, "a")
|
||||
fmt.Println(res1) //1
|
||||
|
||||
res2 := slice.LastIndexOf(arr, "d")
|
||||
fmt.Println(res2) //-1
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Map">Map</span>
|
||||
<p>通过运行函数slice中的每个元素来创建一个新切片</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Map[T any, U any](slice []T, iteratee func(index int, t T) U) []U
|
||||
func Map[T any, U any](slice []T, iteratee func(index int, item T) U) []U
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -759,12 +817,12 @@ func main() {
|
||||
|
||||
|
||||
### <span id="Reduce">Reduce</span>
|
||||
<p>将slice中的元素依次运行函数,返回运行结果</p>
|
||||
<p>将切片中的元素依次运行iteratee函数,返回运行结果</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Reduce[T any](slice []T, iteratee func(index int, t1, t2 T) T, initial T) T
|
||||
func Reduce[T any](slice []T, iteratee func(index int, item1, item2 T) T, initial T) T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -861,7 +919,7 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Some[T any](slice []T, predicate func(index int, t T) bool) bool
|
||||
func Some[T any](slice []T, predicate func(index int, item T) bool) bool
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -963,7 +1021,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="Union">Unique</span>
|
||||
<p>从所有给定的切片按顺序创建一个唯一值切片。 使用 == 进行相等比较。</p>
|
||||
<p>从所有给定的切片按顺序创建一个唯一值切片,使用==进行相等比较</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -990,7 +1048,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="UpdateAt">UpdateAt</span>
|
||||
<p>更新索引处的切片元素。 如果 param index < 0 或 index >= len(slice),将返回错误</p>
|
||||
<p>更新索引处的切片元素。 如果index < 0或 index >= len(slice),将返回错误</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ import (
|
||||
- [PadStart](#PadStart)
|
||||
- [ReverseStr](#ReverseStr)
|
||||
- [SnakeCase](#SnakeCase)
|
||||
- [SplitEx](#SplitEx)
|
||||
- [Wrap](#Wrap)
|
||||
|
||||
- [Unwrap](#Unwrap)
|
||||
@@ -493,6 +494,43 @@ func main() {
|
||||
|
||||
|
||||
|
||||
### <span id="SplitEx">SplitEx</span>
|
||||
<p>Split a given string whether the result contains empty string.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func SplitEx(s, sep string, removeEmptyString bool) []string
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
arr1 := strutil.SplitEx(" a b c ", "", true)
|
||||
fmt.Println(arr1) //[]string{}
|
||||
|
||||
arr2 := strutil.SplitEx(" a b c ", " ", false)
|
||||
fmt.Println(arr2) //[]string{"", "a", "b", "c", ""}
|
||||
|
||||
arr3 := strutil.SplitEx(" a b c ", " ", true)
|
||||
fmt.Println(arr3) //[]string{"a", "b", "c"}
|
||||
|
||||
arr4 := strutil.SplitEx(" a = b = c = ", " = ", false)
|
||||
fmt.Println(arr4) //[]string{" a", "b", "c", ""}
|
||||
|
||||
arr5 := strutil.SplitEx(" a = b = c = ", " = ", true)
|
||||
fmt.Println(arr5) //[]string{" a", "b", "c"}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Wrap">Wrap</span>
|
||||
<p>Wrap a string with another string.</p>
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ import (
|
||||
- [PadStart](#PadStart)
|
||||
- [ReverseStr](#ReverseStr)
|
||||
- [SnakeCase](#SnakeCase)
|
||||
- [SplitEx](#SplitEx)
|
||||
- [Wrap](#Wrap)
|
||||
|
||||
- [Unwrap](#Unwrap)
|
||||
@@ -493,6 +494,41 @@ func main() {
|
||||
|
||||
|
||||
|
||||
### <span id="SplitEx">SplitEx</span>
|
||||
<p>分割字符串为切片,removeEmptyString参数指定是否去除空字符串</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func SplitEx(s, sep string, removeEmptyString bool) []string
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
arr1 := strutil.SplitEx(" a b c ", "", true)
|
||||
fmt.Println(arr1) //[]string{}
|
||||
|
||||
arr2 := strutil.SplitEx(" a b c ", " ", false)
|
||||
fmt.Println(arr2) //[]string{"", "a", "b", "c", ""}
|
||||
|
||||
arr3 := strutil.SplitEx(" a b c ", " ", true)
|
||||
fmt.Println(arr3) //[]string{"a", "b", "c"}
|
||||
|
||||
arr4 := strutil.SplitEx(" a = b = c = ", " = ", false)
|
||||
fmt.Println(arr4) //[]string{" a", "b", "c", ""}
|
||||
|
||||
arr5 := strutil.SplitEx(" a = b = c = ", " = ", true)
|
||||
fmt.Println(arr5) //[]string{" a", "b", "c"}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Wrap">Wrap</span>
|
||||
<p>用另一个字符串包裹一个字符串</p>
|
||||
|
||||
@@ -209,7 +209,7 @@ func main() {
|
||||
|
||||
|
||||
|
||||
### <span id="ExecCommand">CompareOsEnv</span>
|
||||
### <span id="ExecCommand">ExecCommand</span>
|
||||
<p>使用shell /bin/bash -c(linux) 或 cmd (windows) 执行shell命令</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -106,6 +106,27 @@ func Max[T lancetconstraints.Number](numbers ...T) T {
|
||||
return max
|
||||
}
|
||||
|
||||
// MaxBy search the maximum value of a slice using the given comparator function.
|
||||
func MaxBy[T any](slice []T, comparator func(T, T) bool) T {
|
||||
var max T
|
||||
|
||||
if len(slice) == 0 {
|
||||
return max
|
||||
}
|
||||
|
||||
max = slice[0]
|
||||
|
||||
for i := 1; i < len(slice); i++ {
|
||||
val := slice[i]
|
||||
|
||||
if comparator(val, max) {
|
||||
max = val
|
||||
}
|
||||
}
|
||||
|
||||
return max
|
||||
}
|
||||
|
||||
// Min return min value of params
|
||||
func Min[T lancetconstraints.Number](numbers ...T) T {
|
||||
min := numbers[0]
|
||||
@@ -119,6 +140,27 @@ func Min[T lancetconstraints.Number](numbers ...T) T {
|
||||
return min
|
||||
}
|
||||
|
||||
// MinBy search the minimum value of a slice using the given comparator function.
|
||||
func MinBy[T any](slice []T, comparator func(T, T) bool) T {
|
||||
var min T
|
||||
|
||||
if len(slice) == 0 {
|
||||
return min
|
||||
}
|
||||
|
||||
min = slice[0]
|
||||
|
||||
for i := 1; i < len(slice); i++ {
|
||||
val := slice[i]
|
||||
|
||||
if comparator(val, min) {
|
||||
min = val
|
||||
}
|
||||
}
|
||||
|
||||
return min
|
||||
}
|
||||
|
||||
// Average return average value of params
|
||||
func Average[T lancetconstraints.Number](numbers ...T) T {
|
||||
var sum T
|
||||
|
||||
@@ -89,6 +89,25 @@ func TestMax(t *testing.T) {
|
||||
assert.Equal(Max(1.2, 1.4, 1.1, 1.4), 1.4)
|
||||
}
|
||||
|
||||
func TestMaxBy(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "MaxBy")
|
||||
|
||||
res1 := MaxBy([]string{"a", "ab", "abc"}, func(v1, v2 string) bool {
|
||||
return len(v1) > len(v2)
|
||||
})
|
||||
assert.Equal("abc", res1)
|
||||
|
||||
res2 := MaxBy([]string{"abd", "abc", "ab"}, func(v1, v2 string) bool {
|
||||
return len(v1) > len(v2)
|
||||
})
|
||||
assert.Equal("abd", res2)
|
||||
|
||||
res3 := MaxBy([]string{}, func(v1, v2 string) bool {
|
||||
return len(v1) > len(v2)
|
||||
})
|
||||
assert.Equal("", res3)
|
||||
}
|
||||
|
||||
func TestMin(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestMin")
|
||||
|
||||
@@ -96,3 +115,22 @@ func TestMin(t *testing.T) {
|
||||
assert.Equal(Min(1, 2, 3), 1)
|
||||
assert.Equal(Min(1.2, 1.4, 1.1, 1.4), 1.1)
|
||||
}
|
||||
|
||||
func TestMinBy(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestMinBy")
|
||||
|
||||
res1 := MinBy([]string{"a", "ab", "abc"}, func(v1, v2 string) bool {
|
||||
return len(v1) < len(v2)
|
||||
})
|
||||
assert.Equal("a", res1)
|
||||
|
||||
res2 := MinBy([]string{"ab", "ac", "abc"}, func(v1, v2 string) bool {
|
||||
return len(v1) < len(v2)
|
||||
})
|
||||
assert.Equal("ab", res2)
|
||||
|
||||
res3 := MinBy([]string{}, func(v1, v2 string) bool {
|
||||
return len(v1) < len(v2)
|
||||
})
|
||||
assert.Equal("", res3)
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ func Difference[T comparable](slice, comparedSlice []T) []T {
|
||||
// DifferenceBy it accepts iteratee which is invoked for each element of slice
|
||||
// and values to generate the criterion by which they're compared.
|
||||
// like lodash.js differenceBy: https://lodash.com/docs/4.17.15#differenceBy,
|
||||
func DifferenceBy[T any](slice []T, comparedSlice []T, iteratee func(index int, t T) T) []T {
|
||||
func DifferenceBy[T any](slice []T, comparedSlice []T, iteratee func(index int, item T) T) []T {
|
||||
orginSliceAfterMap := Map(slice, iteratee)
|
||||
comparedSliceAfterMap := Map(comparedSlice, iteratee)
|
||||
|
||||
@@ -148,7 +148,7 @@ func DifferenceWith[T any](slice []T, comparedSlice []T, comparator func(value,
|
||||
}
|
||||
|
||||
// Every return true if all of the values in the slice pass the predicate function.
|
||||
func Every[T any](slice []T, predicate func(index int, t T) bool) bool {
|
||||
func Every[T any](slice []T, predicate func(index int, item T) bool) bool {
|
||||
if predicate == nil {
|
||||
panic("predicate func is missing")
|
||||
}
|
||||
@@ -164,7 +164,7 @@ func Every[T any](slice []T, predicate func(index int, t T) bool) bool {
|
||||
}
|
||||
|
||||
// None return true if all the values in the slice mismatch the criteria
|
||||
func None[T any](slice []T, predicate func(index int, t T) bool) bool {
|
||||
func None[T any](slice []T, predicate func(index int, item T) bool) bool {
|
||||
if predicate == nil {
|
||||
panic("predicate func is missing")
|
||||
}
|
||||
@@ -180,7 +180,7 @@ func None[T any](slice []T, predicate func(index int, t T) bool) bool {
|
||||
}
|
||||
|
||||
// Some return true if any of the values in the list pass the predicate function.
|
||||
func Some[T any](slice []T, predicate func(index int, t T) bool) bool {
|
||||
func Some[T any](slice []T, predicate func(index int, item T) bool) bool {
|
||||
if predicate == nil {
|
||||
panic("predicate func is missing")
|
||||
}
|
||||
@@ -194,7 +194,7 @@ func Some[T any](slice []T, predicate func(index int, t T) bool) bool {
|
||||
}
|
||||
|
||||
// Filter iterates over elements of slice, returning an slice of all elements pass the predicate function
|
||||
func Filter[T any](slice []T, predicate func(index int, t T) bool) []T {
|
||||
func Filter[T any](slice []T, predicate func(index int, item T) bool) []T {
|
||||
if predicate == nil {
|
||||
panic("predicate func is missing")
|
||||
}
|
||||
@@ -209,7 +209,7 @@ func Filter[T any](slice []T, predicate func(index int, t T) bool) []T {
|
||||
}
|
||||
|
||||
// Count iterates over elements of slice, returns a count of all matched elements
|
||||
func Count[T any](slice []T, predicate func(index int, t T) bool) int {
|
||||
func Count[T any](slice []T, predicate func(index int, item T) bool) int {
|
||||
if predicate == nil {
|
||||
panic("predicate func is missing")
|
||||
}
|
||||
@@ -229,7 +229,7 @@ func Count[T any](slice []T, predicate func(index int, t T) bool) int {
|
||||
}
|
||||
|
||||
// GroupBy iterate over elements of the slice, each element will be group by criteria, returns two slices
|
||||
func GroupBy[T any](slice []T, groupFn func(index int, t T) bool) ([]T, []T) {
|
||||
func GroupBy[T any](slice []T, groupFn func(index int, item T) bool) ([]T, []T) {
|
||||
if groupFn == nil {
|
||||
panic("groupFn func is missing")
|
||||
}
|
||||
@@ -274,7 +274,7 @@ func GroupWith[T any, U comparable](slice []T, iteratee func(T) U) map[U][]T {
|
||||
|
||||
// Find iterates over elements of slice, returning the first one that passes a truth test on predicate function.
|
||||
// If return T is nil then no items matched the predicate func
|
||||
func Find[T any](slice []T, predicate func(index int, t T) bool) (*T, bool) {
|
||||
func Find[T any](slice []T, predicate func(index int, item T) bool) (*T, bool) {
|
||||
if predicate == nil {
|
||||
panic("predicate func is missing")
|
||||
}
|
||||
@@ -300,7 +300,7 @@ func Find[T any](slice []T, predicate func(index int, t T) bool) (*T, bool) {
|
||||
|
||||
// FindLast iterates over elements of slice from end to begin, returning the first one that passes a truth test on predicate function.
|
||||
// If return T is nil then no items matched the predicate func
|
||||
func FindLast[T any](slice []T, predicate func(index int, t T) bool) (*T, bool) {
|
||||
func FindLast[T any](slice []T, predicate func(index int, item T) bool) (*T, bool) {
|
||||
if predicate == nil {
|
||||
panic("predicate func is missing")
|
||||
}
|
||||
@@ -349,7 +349,7 @@ func flattenRecursive(value reflect.Value, result reflect.Value) reflect.Value {
|
||||
}
|
||||
|
||||
// ForEach iterates over elements of slice and invokes function for each element
|
||||
func ForEach[T any](slice []T, iteratee func(index int, t T)) {
|
||||
func ForEach[T any](slice []T, iteratee func(index int, item T)) {
|
||||
if iteratee == nil {
|
||||
panic("iteratee func is missing")
|
||||
}
|
||||
@@ -360,7 +360,7 @@ func ForEach[T any](slice []T, iteratee func(index int, t T)) {
|
||||
}
|
||||
|
||||
// Map creates an slice of values by running each element of slice thru iteratee function.
|
||||
func Map[T any, U any](slice []T, iteratee func(index int, t T) U) []U {
|
||||
func Map[T any, U any](slice []T, iteratee func(index int, item T) U) []U {
|
||||
if iteratee == nil {
|
||||
panic("iteratee func is missing")
|
||||
}
|
||||
@@ -374,7 +374,7 @@ func Map[T any, U any](slice []T, iteratee func(index int, t T) U) []U {
|
||||
}
|
||||
|
||||
// Reduce creates an slice of values by running each element of slice thru iteratee function.
|
||||
func Reduce[T any](slice []T, iteratee func(index int, t1, t2 T) T, initial T) T {
|
||||
func Reduce[T any](slice []T, iteratee func(index int, item1, item2 T) T, initial T) T {
|
||||
if iteratee == nil {
|
||||
panic("iteratee func is missing")
|
||||
}
|
||||
@@ -733,3 +733,27 @@ func Without[T any](slice []T, values ...T) []T {
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// IndexOf returns the index at which the first occurrence of a value is found in a slice or return -1
|
||||
// if the value cannot be found.
|
||||
func IndexOf[T any](slice []T, value T) int {
|
||||
for i, v := range slice {
|
||||
if reflect.DeepEqual(v, value) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
// LastIndexOf returns the index at which the last occurrence of a value is found in a slice or return -1
|
||||
// if the value cannot be found.
|
||||
func LastIndexOf[T any](slice []T, value T) int {
|
||||
for i := len(slice) - 1; i > 0; i-- {
|
||||
if reflect.DeepEqual(value, slice[i]) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
@@ -530,3 +530,19 @@ func TestShuffle(t *testing.T) {
|
||||
|
||||
assert.Equal(5, len(res))
|
||||
}
|
||||
|
||||
func TestIndexOf(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestIndexOf")
|
||||
|
||||
arr := []string{"a", "a", "b", "c"}
|
||||
assert.Equal(0, IndexOf(arr, "a"))
|
||||
assert.Equal(-1, IndexOf(arr, "d"))
|
||||
}
|
||||
|
||||
func TestLastIndexOf(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestLastIndexOf")
|
||||
|
||||
arr := []string{"a", "a", "b", "c"}
|
||||
assert.Equal(1, LastIndexOf(arr, "a"))
|
||||
assert.Equal(-1, LastIndexOf(arr, "d"))
|
||||
}
|
||||
|
||||
@@ -247,3 +247,52 @@ func Unwrap(str string, wrapToken string) string {
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
// SplitEx split a given string whether the result contains empty string
|
||||
func SplitEx(s, sep string, removeEmptyString bool) []string {
|
||||
if sep == "" {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
n := strings.Count(s, sep) + 1
|
||||
a := make([]string, n)
|
||||
n--
|
||||
i := 0
|
||||
sepSave := 0
|
||||
ignore := false
|
||||
|
||||
for i < n {
|
||||
m := strings.Index(s, sep)
|
||||
if m < 0 {
|
||||
break
|
||||
}
|
||||
ignore = false
|
||||
if removeEmptyString {
|
||||
if s[:m+sepSave] == "" {
|
||||
ignore = true
|
||||
}
|
||||
}
|
||||
if !ignore {
|
||||
a[i] = s[:m+sepSave]
|
||||
s = s[m+len(sep):]
|
||||
i++
|
||||
} else {
|
||||
s = s[m+len(sep):]
|
||||
}
|
||||
}
|
||||
|
||||
var ret []string
|
||||
if removeEmptyString {
|
||||
if s != "" {
|
||||
a[i] = s
|
||||
ret = a[:i+1]
|
||||
} else {
|
||||
ret = a[:i]
|
||||
}
|
||||
} else {
|
||||
a[i] = s
|
||||
ret = a[:i+1]
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
@@ -177,3 +177,15 @@ func TestUnwrap(t *testing.T) {
|
||||
assert.Equal("***", Unwrap("***", "**"))
|
||||
assert.Equal("**", Unwrap("**", "**"))
|
||||
}
|
||||
|
||||
func TestSplitEx(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSplitEx")
|
||||
|
||||
assert.Equal([]string{}, SplitEx(" a b c ", "", true))
|
||||
|
||||
assert.Equal([]string{"", "a", "b", "c", ""}, SplitEx(" a b c ", " ", false))
|
||||
assert.Equal([]string{"a", "b", "c"}, SplitEx(" a b c ", " ", true))
|
||||
|
||||
assert.Equal([]string{" a", "b", "c", ""}, SplitEx(" a = b = c = ", " = ", false))
|
||||
assert.Equal([]string{" a", "b", "c"}, SplitEx(" a = b = c = ", " = ", true))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user