mirror of
https://github.com/duke-git/lancet.git
synced 2026-03-01 00:35:28 +08:00
Compare commits
78 Commits
v2.1.11
...
cc68feb52d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cc68feb52d | ||
|
|
ca2a51b37e | ||
|
|
be444f521d | ||
|
|
e21dd07d46 | ||
|
|
4044deac70 | ||
|
|
d9c6294775 | ||
|
|
d8505d1a5f | ||
|
|
6498c7d68a | ||
|
|
5f0211f0c4 | ||
|
|
1de2e2cedd | ||
|
|
c8f8b1b7d9 | ||
|
|
3062eb7789 | ||
|
|
64d5486cc6 | ||
|
|
6d57891f66 | ||
|
|
927245e47f | ||
|
|
31fdbee0b5 | ||
|
|
3712819994 | ||
|
|
6d7dec1cea | ||
|
|
9b6a004dbc | ||
|
|
3ad6f4bd9e | ||
|
|
b8c6746f31 | ||
|
|
0bf8bbf4cb | ||
|
|
a6ba1028c5 | ||
|
|
cc54dd7ec9 | ||
|
|
54834dba4c | ||
|
|
e996d4c945 | ||
|
|
ae92ae7666 | ||
|
|
526e568d0e | ||
|
|
1dc5e8ac23 | ||
|
|
b5f7b0e670 | ||
|
|
39c576248c | ||
|
|
eb164d1536 | ||
|
|
68e170080c | ||
|
|
652b09135c | ||
|
|
bff24c89bc | ||
|
|
49a460eef8 | ||
|
|
a58e52e53c | ||
|
|
b07356423f | ||
|
|
005dd9d2ab | ||
|
|
65315dafb1 | ||
|
|
b06fb6736d | ||
|
|
b9f0854950 | ||
|
|
6a2dd328ad | ||
|
|
dd1147f6d0 | ||
|
|
6da7ce64af | ||
|
|
b7e5d946f1 | ||
|
|
687db4ce79 | ||
|
|
a9a4bb8841 | ||
|
|
bc6cb5f61b | ||
|
|
2c57266f8e | ||
|
|
57e49c9520 | ||
|
|
985c9a5d9a | ||
|
|
5cfb11f036 | ||
|
|
5b3d48a1e7 | ||
|
|
d0576e028f | ||
|
|
76bdec2b54 | ||
|
|
fa20aba3a7 | ||
|
|
7a4a429e23 | ||
|
|
a70ec6ad1e | ||
|
|
e435fa271b | ||
|
|
1533d00891 | ||
|
|
8b99641de0 | ||
|
|
251f899f18 | ||
|
|
00407e5182 | ||
|
|
4e457ad672 | ||
|
|
7d8d9c3543 | ||
|
|
1197e8d1b6 | ||
|
|
13bbe19ab2 | ||
|
|
2725575d2f | ||
|
|
037d2729ce | ||
|
|
09d98745b0 | ||
|
|
af5cfe6da1 | ||
|
|
d59259bbe0 | ||
|
|
3189628d54 | ||
|
|
62c5e251a5 | ||
|
|
6e6444c8c0 | ||
|
|
dd613e98b2 | ||
|
|
2d905ab03e |
852
README.md
852
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)
|
||||
@@ -19,7 +19,7 @@
|
||||
Lancet is a comprehensive, efficient, and reusable util function library of go. Inspired by the java apache common package and lodash.js.
|
||||
</p>
|
||||
|
||||
English | [简体中文](./README_zh-CN.md) | [Website](https://uvdream.github.io/lancet-docs/en/)
|
||||
English | [简体中文](./README_zh-CN.md)
|
||||
|
||||
## Feature
|
||||
|
||||
@@ -32,16 +32,16 @@ English | [简体中文](./README_zh-CN.md) | [Website](https://uvdream.github.i
|
||||
|
||||
### Note:
|
||||
|
||||
1. <b>For users who use go1.18 and above, it is recommended to install lancet v2.x.x. Cause v2.x.x rewrite all functions with generics of go1.18.</b>
|
||||
1. <b>For users who use go1.18 and above, it is recommended to install lancet v2.x.x. Cause in v2.x.x all functions was rewriten with generics of go1.18.</b>
|
||||
|
||||
```go
|
||||
go get github.com/duke-git/lancet/v2 // will install latest version of v2.x.x
|
||||
```
|
||||
|
||||
2. <b>For users who use version below go1.18, you should install v1.x.x. now latest v1 is v1.3.4. </b>
|
||||
2. <b>For users who use version below go1.18, you should install v1.x.x. The latest of v1.x.x is v1.3.5. </b>
|
||||
|
||||
```go
|
||||
go get github.com/duke-git/lancet@v1.3.3 // below go1.18, install latest version of v1.x.x
|
||||
go get github.com/duke-git/lancet@v1.3.5 // below go1.18, install latest version of v1.x.x
|
||||
```
|
||||
|
||||
## Usage
|
||||
@@ -71,9 +71,7 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
## API Documentation
|
||||
|
||||
## [lancet API doc](https://uvdream.github.io/lancet-docs/) Thanks [@UvDream](https://github.com/UvDream) for contributing.
|
||||
## Documentation
|
||||
|
||||
### 1. Algorithm package implements some basic algorithm. eg. sort, search.
|
||||
|
||||
@@ -83,18 +81,41 @@ import "github.com/duke-git/lancet/v2/algorithm"
|
||||
|
||||
#### Function list:
|
||||
|
||||
- [BubbleSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#BubbleSort)
|
||||
- [CountSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#CountSort)
|
||||
- [HeapSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#HeapSort)
|
||||
- [InsertionSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#InsertionSort)
|
||||
- [MergeSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#MergeSort)
|
||||
- [QuickSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#QuickSort)
|
||||
- [SelectionSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#SelectionSort)
|
||||
- [ShellSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#ShellSort)
|
||||
- [BinarySearch](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#BinarySearch)
|
||||
- [BinaryIterativeSearch](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#BinaryIterativeSearch)
|
||||
- [LinearSearch](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#LinearSearch)
|
||||
- [LRUCache](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#LRUCache)
|
||||
- **<big>BubbleSort</big>** : sorts slice with bubble sort algorithm, will change the original slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#BubbleSort)]
|
||||
[[play](https://go.dev/play/p/GNdv7Jg2Taj)]
|
||||
- **<big>CountSort</big>** : sorts slice with bubble sort algorithm, don't change original slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#CountSort)]
|
||||
[[play](https://go.dev/play/p/tB-Umgm0DrP)]
|
||||
- **<big>HeapSort</big>** : sorts slice with heap sort algorithm, will change the original slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#HeapSort)]
|
||||
[[play](https://go.dev/play/p/u6Iwa1VZS_f)]
|
||||
- **<big>InsertionSort</big>** : sorts slice with insertion sort algorithm, will change the original slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#InsertionSort)]
|
||||
[[play](https://go.dev/play/p/G5LJiWgJJW6)]
|
||||
- **<big>MergeSort</big>** : sorts slice with merge sort algorithm, will change the original slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#MergeSort)]
|
||||
[[play](https://go.dev/play/p/ydinn9YzUJn)]
|
||||
- **<big>QuickSort</big>** : sorts slice with quick sort algorithm, will change the original slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#QuickSort)]
|
||||
[[play](https://go.dev/play/p/7Y7c1Elk3ax)]
|
||||
- **<big>SelectionSort</big>** : sorts slice with selection sort algorithm, will change the original slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#SelectionSort)]
|
||||
[[play](https://go.dev/play/p/oXovbkekayS)]
|
||||
- **<big>ShellSort</big>** : sorts slice with shell sort algorithm, will change the original slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#ShellSort)]
|
||||
[[play](https://go.dev/play/p/3ibkszpJEu3)]
|
||||
- **<big>BinarySearch</big>** : returns the index of target within a sorted slice, use binary search (recursive call itself).
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#BinarySearch)]
|
||||
[[play](https://go.dev/play/p/t6MeGiUSN47)]
|
||||
- **<big>BinaryIterativeSearch</big>** : returns the index of target within a sorted slice, use binary search (no recursive).
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#BinaryIterativeSearch)]
|
||||
[[play](https://go.dev/play/p/Anozfr8ZLH3)]
|
||||
- **<big>LinearSearch</big>** : returns the index of target in slice base on equal function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#LinearSearch)]
|
||||
- **<big>LRUCache</big>** : implements memory cache with lru algorithm.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#LRUCache)]
|
||||
[[play](https://go.dev/play/p/-EZjgOURufP)]
|
||||
|
||||
### 2. Concurrency package contain some functions to support concurrent programming. eg, goroutine, channel, async.
|
||||
|
||||
@@ -104,16 +125,26 @@ 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)
|
||||
- **<big>NewChannel</big>** : create a Channel pointer instance.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#NewChannel)]
|
||||
- **<big>Bridge</big>** : link multiply channels into one channel.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/Bridge.md#NewChannel)]
|
||||
- **<big>FanIn</big>** : merge multiple channels into one channel.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#FanIn)]
|
||||
- **<big>Generate</big>** : creates a channel, then put values into the channel.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Generate)]
|
||||
- **<big>Or</big>** : read one or more channels into one channel, will close when any readin channel is closed.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Or)]
|
||||
- **<big>OrDone</big>** : read a channel into another channel, will close until cancel context.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#OrDone)]
|
||||
- **<big>Repeat</big>** : create channel, put values into the channel repeatly until cancel the context.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Repeat)]
|
||||
- **<big>RepeatFn</big>** : create a channel, excutes fn repeatly, and put the result into the channel, until close context.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#RepeatFn)]
|
||||
- **<big>Take</big>** : create a channel whose values are taken from another channel with limit number.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Take)]
|
||||
- **<big>Tee</big>** : split one chanel into two channels, until cancel the context.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Tee)]
|
||||
|
||||
### 3. Condition package contains some functions for conditional judgment. eg. And, Or, TernaryOperator...
|
||||
|
||||
@@ -123,13 +154,30 @@ import "github.com/duke-git/lancet/v2/condition"
|
||||
|
||||
#### Function list:
|
||||
|
||||
- [Bool](https://github.com/duke-git/lancet/blob/main/docs/condition.md#Bool)
|
||||
- [And](https://github.com/duke-git/lancet/blob/main/docs/condition.md#And)
|
||||
- [Or](https://github.com/duke-git/lancet/blob/main/docs/condition.md#Or)
|
||||
- [Xor](https://github.com/duke-git/lancet/blob/main/docs/condition.md#Xor)
|
||||
- [Nor](https://github.com/duke-git/lancet/blob/main/docs/condition.md#Nor)
|
||||
- [Nand](https://github.com/duke-git/lancet/blob/main/docs/condition.md#Nand)
|
||||
- [TernaryOperator](https://github.com/duke-git/lancet/blob/main/docs/condition.md#TernaryOperator)
|
||||
- **<big>Bool</big>** : returns the truthy value of anything.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/condition.md#Bool)]
|
||||
[[play](https://go.dev/play/p/ETzeDJRSvhm)]
|
||||
- **<big>And</big>** : returns true if both a and b are truthy.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/condition.md#And)]
|
||||
[[play](https://go.dev/play/p/W1SSUmt6pvr)]
|
||||
- **<big>Or</big>** : returns false if neither a nor b is truthy.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/condition.md#Or)]
|
||||
[[play](https://go.dev/play/p/UlQTxHaeEkq)]
|
||||
- **<big>Xor</big>** : returns true if a or b but not both is truthy.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/condition.md#Xor)]
|
||||
[[play](https://go.dev/play/p/gObZrW7ZbG8)]
|
||||
- **<big>Nor</big>** : returns true if neither a nor b is truthy.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/condition.md#Nor)]
|
||||
[[play](https://go.dev/play/p/g2j08F_zZky)
|
||||
- **<big>Xnor</big>** : returns true if both a and b or neither a nor b are truthy.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/condition.md#Xnor)]
|
||||
[[play](https://go.dev/play/p/OuDB9g51643)]
|
||||
- **<big>Nand</big>** : returns false if both a and b are truthy.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/condition.md#Nand)]
|
||||
[[play](https://go.dev/play/p/vSRMLxLIbq8)]
|
||||
- **<big>TernaryOperator</big>** : ternary operator.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/condition.md#TernaryOperator)]
|
||||
[[play](https://go.dev/play/p/ElllPZY0guT)]
|
||||
|
||||
### 4. Convertor package contains some functions for data convertion.
|
||||
|
||||
@@ -139,22 +187,54 @@ import "github.com/duke-git/lancet/v2/convertor"
|
||||
|
||||
#### Function list:
|
||||
|
||||
- [ColorHexToRGB](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ColorHexToRGB)
|
||||
- [ColorRGBToHex](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ColorRGBToHex)
|
||||
- [ToBool](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToBool)
|
||||
- [ToBytes](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToBytes)
|
||||
- [ToChar](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToChar)
|
||||
- [ToChannel](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToChannel)
|
||||
- [ToFloat](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToFloat)
|
||||
- [ToInt](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToInt)
|
||||
- [ToJson](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToJson)
|
||||
- [ToMap](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToMap)
|
||||
- [ToPointer](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToPointer)
|
||||
- [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)
|
||||
- [MapToSlice](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#MapToSlice)
|
||||
- [EncodeByte](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#EncodeByte)
|
||||
- [DecodeByte](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#DecodeByte)
|
||||
- **<big>ColorHexToRGB</big>** : convert color hex to color rgb.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ColorHexToRGB)]
|
||||
[[play](https://go.dev/play/p/o7_ft-JCJBV)]
|
||||
- **<big>ColorRGBToHex</big>** : convert rgb color to hex color.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ColorRGBToHex)]
|
||||
[[play](https://go.dev/play/p/nzKS2Ro87J1)]
|
||||
- **<big>ToBool</big>** : convert string to bool.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToBool)]
|
||||
[[play](https://go.dev/play/p/ARht2WnGdIN)]
|
||||
- **<big>ToBytes</big>** : convert value to byte slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToBytes)]
|
||||
[[play](https://go.dev/play/p/fAMXYFDvOvr)]
|
||||
- **<big>ToChar</big>** : convert string to char slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToChar)]
|
||||
[[play](https://go.dev/play/p/JJ1SvbFkVdM)]
|
||||
- **<big>ToChannel</big>** : convert a collection of elements to a read-only channel.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToChannel)]
|
||||
[[play](https://go.dev/play/p/hOx_oYZbAnL)]
|
||||
- **<big>ToFloat</big>** : convert value to float64, if param is a invalid floatable, will return 0.0 and error.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToFloat)]
|
||||
[[play](https://go.dev/play/p/4YTmPCibqHJ)]
|
||||
- **<big>ToInt</big>** : convert value to int64 value, if input is not numerical, return 0 and error.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToInt)]
|
||||
[[play](https://go.dev/play/p/9_h9vIt-QZ_b)]
|
||||
- **<big>ToJson</big>** : convert value to a json string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToJson)]
|
||||
[[play](https://go.dev/play/p/2rLIkMmXWvR)]
|
||||
- **<big>ToMap</big>** : convert a slice of structs to a map based on iteratee function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToMap)]
|
||||
[[play](https://go.dev/play/p/tVFy7E-t24l)]
|
||||
- **<big>ToPointer</big>** : return a pointer of passed value.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToPointer)]
|
||||
[[play](https://go.dev/play/p/ASf_etHNlw1)]
|
||||
- **<big>ToString</big>** : convert value to string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToString)]
|
||||
[[play](https://go.dev/play/p/nF1zOOslpQq)]
|
||||
- **<big>StructToMap</big>** : convert struct to map, only convert exported struct field.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#StructToMap)]
|
||||
[[play](https://go.dev/play/p/KYGYJqNUBOI)]
|
||||
- **<big>MapToSlice</big>** : convert map to slice based on iteratee function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#MapToSlice)]
|
||||
[[play](https://go.dev/play/p/dmX4Ix5V6Wl)]
|
||||
- **<big>EncodeByte</big>** : encode data to byte slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#EncodeByte)]
|
||||
[[play](https://go.dev/play/p/DVmM1G5JfuP)]
|
||||
- **<big>DecodeByte</big>** : decode byte slice data to target object.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#DecodeByte)]
|
||||
[[play](https://go.dev/play/p/zI6xsmuQRbn)]
|
||||
|
||||
### 5. Cryptor package is for data encryption and decryption.
|
||||
|
||||
@@ -268,21 +348,51 @@ import "github.com/duke-git/lancet/v2/fileutil"
|
||||
|
||||
#### Function list:
|
||||
|
||||
- [ClearFile](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#ClearFile)
|
||||
- [CreateFile](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#CreateFile)
|
||||
- [CreateDir](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#CreateDir)
|
||||
- [CopyFile](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#CopyFile)
|
||||
- [FileMode](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#FileMode)
|
||||
- [MiMeType](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#MiMeType)
|
||||
- [IsExist](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#IsExist)
|
||||
- [IsLink](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#IsLink)
|
||||
- [IsDir](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#IsDir)
|
||||
- [ListFileNames](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#ListFileNames)
|
||||
- [RemoveFile](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#RemoveFile)
|
||||
- [ReadFileToString](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#ReadFileToString)
|
||||
- [ReadFileByLine](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#ReadFileByLine)
|
||||
- [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)
|
||||
- **<big>ClearFile</big>** : write empty string to target file.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#ClearFile)]
|
||||
[[play](https://go.dev/play/p/NRZ0ZT-G94H)]
|
||||
- **<big>CreateFile</big>** : create file in path.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#CreateFile)]
|
||||
[[play](https://go.dev/play/p/lDt8PEsTNKI)]
|
||||
- **<big>CreateDir</big>** : create directory in absolute path.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#CreateDir)]
|
||||
[[play](https://go.dev/play/p/qUuCe1OGQnM)]
|
||||
- **<big>CopyFile</big>** :copy src file to dest file.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#CopyFile)]
|
||||
[[play](https://go.dev/play/p/Jg9AMJMLrJi)]
|
||||
- **<big>FileMode</big>** : return file's mode and permission.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#FileMode)]
|
||||
[[play](https://go.dev/play/p/2l2hI42fA3p)]
|
||||
- **<big>MiMeType</big>** : return file mime type.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#MiMeType)]
|
||||
[[play](https://go.dev/play/p/bd5sevSUZNu)]
|
||||
- **<big>IsExist</big>** : checks if a file or directory exists.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#IsExist)]
|
||||
[[play](https://go.dev/play/p/nKKXt8ZQbmh)]
|
||||
- **<big>IsLink</big>** : checks if a file is symbol link or not.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#IsLink)]
|
||||
[[play](https://go.dev/play/p/TL-b-Kzvf44)]
|
||||
- **<big>IsDir</big>** : checks if the path is directory or not.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#IsDir)]
|
||||
[[play](https://go.dev/play/p/WkVwEKqtOWk)]
|
||||
- **<big>ListFileNames</big>** : return all file names in the path.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#ListFileNames)]
|
||||
[[play](https://go.dev/play/p/Tjd7Y07rejl)]
|
||||
- **<big>RemoveFile</big>** : remove file, param should be file path.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#RemoveFile)]
|
||||
[[play](https://go.dev/play/p/P2y0XW8a1SH)]
|
||||
- **<big>ReadFileToString</big>** : return string of file content.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#ReadFileToString)]
|
||||
[[play](https://go.dev/play/p/cmfwp_5SQTp)]
|
||||
- **<big>ReadFileByLine</big>** : read file line by line, return string slice of file content.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#ReadFileByLine)]
|
||||
[[play](https://go.dev/play/p/svJP_7ZrBrD)]
|
||||
- **<big>Zip</big>** : create zip file.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#Zip)]
|
||||
[[play](https://go.dev/play/p/j-3sWBp8ik_P)]
|
||||
- **<big>UnZip</big>** : unzip the zip file and save it to dest path.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#UnZip)]
|
||||
[[play](https://go.dev/play/p/g0w34kS7B8m)]
|
||||
|
||||
### 9. Formatter contains some functions for data formatting.
|
||||
|
||||
@@ -292,7 +402,9 @@ import "github.com/duke-git/lancet/v2/formatter"
|
||||
|
||||
#### Function list:
|
||||
|
||||
- [Comma](https://github.com/duke-git/lancet/blob/main/docs/formatter.md#Comma)
|
||||
- **<big>Comma</big>** : add comma to a number value by every 3 numbers from right, ahead by symbol char.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter.md#Comma)]
|
||||
[[play](https://go.dev/play/p/eRD5k2vzUVX)]
|
||||
|
||||
### 10. Function package can control the flow of function execution and support part of functional programming
|
||||
|
||||
@@ -302,14 +414,32 @@ import "github.com/duke-git/lancet/v2/function"
|
||||
|
||||
#### Function list:
|
||||
|
||||
- [After](https://github.com/duke-git/lancet/blob/main/docs/function.md#After)
|
||||
- [Before](https://github.com/duke-git/lancet/blob/main/docs/function.md#Before)
|
||||
- [Curry](https://github.com/duke-git/lancet/blob/main/docs/function.md#Curry)
|
||||
- [Compose](https://github.com/duke-git/lancet/blob/main/docs/function.md#Compose)
|
||||
- [Debounced](https://github.com/duke-git/lancet/blob/main/docs/function.md#Debounced)
|
||||
- [Delay](https://github.com/duke-git/lancet/blob/main/docs/function.md#Delay)
|
||||
- [Pipeline](https://github.com/duke-git/lancet/blob/main/docs/function.md#Pipeline)
|
||||
- [Watcher](https://github.com/duke-git/lancet/blob/main/docs/function.md#Watcher)
|
||||
- **<big>After</big>** : return a function that invokes passed funcation once the returned function is called more than n times.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function.md#After)]
|
||||
[[play](https://go.dev/play/p/eRD5k2vzUVX)]
|
||||
- **<big>Before</big>** : return a function that invokes passed funcation once the returned function is called less than n times
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function.md#Before)]
|
||||
[[play](https://go.dev/play/p/0HqUDIFZ3IL)]
|
||||
- **<big>CurryFn</big>** : make a curry function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function.md#CurryFn)]
|
||||
- **<big>Compose</big>** : compose the functions from right to left.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function.md#Compose)]
|
||||
- **<big>Delay</big>** : call the function after delayed time.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function.md#Delay)]
|
||||
[[play](https://go.dev/play/p/Ivtc2ZE-Tye)]
|
||||
- **<big>Debounced</big>** : creates a debounced function that delays invoking fn until after wait duration have elapsed since the last time the debounced function was invoked.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function.md#Debounced)]
|
||||
[[play](https://go.dev/play/p/absuEGB_GN7)]
|
||||
- **<big>Schedule</big>** : invoke function every duration time, util close the returned bool channel.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function.md#Schedule)]
|
||||
[[play](https://go.dev/play/p/hbON-Xeyn5N)]
|
||||
- **<big>Pipeline</big>** : takes a list of functions and returns a function whose param will be passed into the functions one by one.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function.md#Pipeline)]
|
||||
[[play](https://go.dev/play/p/mPdUVvj6HD6)]
|
||||
- **<big>Watcher</big>** : Watcher is used for record code excution time. can start/stop/reset the watch timer. get the elapsed time of function execution.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function.md#Watcher)]
|
||||
|
||||
|
||||
|
||||
### 11. Maputil package includes some functions to manipulate map.
|
||||
|
||||
@@ -319,14 +449,30 @@ import "github.com/duke-git/lancet/v2/maputil"
|
||||
|
||||
#### Function list:
|
||||
|
||||
- [ForEach](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#ForEach)
|
||||
- [Filter](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Filter)
|
||||
- [Intersect](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Intersect)
|
||||
- [Keys](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Keys)
|
||||
- [Merge](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Merge)
|
||||
- [Minus](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Minus)
|
||||
- [Values](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Values)
|
||||
- [IsDisjoint](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#IsDisjoint)
|
||||
- **<big>ForEach</big>** : executes iteratee funcation for every key and value pair in map.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#ForEach)]
|
||||
[[play](https://go.dev/play/p/OaThj6iNVXK)]
|
||||
- **<big>Filter</big>** : iterates over map, return a new map contains all key and value pairs pass the predicate function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Filter)]
|
||||
[[play](https://go.dev/play/p/fSvF3wxuNG7)]
|
||||
- **<big>Intersect</big>** : iterates over maps, return a new map of key and value pairs in all given maps.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Intersect)]
|
||||
[[play](https://go.dev/play/p/Zld0oj3sjcC)]
|
||||
- **<big>Keys</big>** : returns a slice of the map's keys.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Keys)]
|
||||
[[play](https://go.dev/play/p/xNB5bTb97Wd)]
|
||||
- **<big>Merge</big>** : merge maps, next key will overwrite previous key.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Merge)]
|
||||
[[play](https://go.dev/play/p/H95LENF1uB-)]
|
||||
- **<big>Minus</big>** : creates a map of whose key in mapA but not in mapB.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Minus)]
|
||||
[[play](https://go.dev/play/p/3u5U9K7YZ9m)]
|
||||
- **<big>Values</big>** : returns a slice of the map's values.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Values)]
|
||||
[[play](https://go.dev/play/p/CBKdUc5FTW6)]
|
||||
- **<big>IsDisjoint</big>** : check two map are disjoint if they have no keys in common.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#IsDisjoint)]
|
||||
[[play](https://go.dev/play/p/N9qgYg_Ho6f)]
|
||||
|
||||
### 12. Mathutil package implements some functions for math calculation.
|
||||
|
||||
@@ -336,18 +482,41 @@ import "github.com/duke-git/lancet/v2/mathutil"
|
||||
|
||||
#### Function list:
|
||||
|
||||
- [Average](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Average)
|
||||
- [Exponent](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Exponent)
|
||||
- [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)
|
||||
- **<big>Average</big>** :return average value of numbers.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Average)]
|
||||
[[play](https://go.dev/play/p/Vv7LBwER-pz)]
|
||||
- **<big>Exponent</big>** : calculate x^n for int64.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Exponent)]
|
||||
[[play](https://go.dev/play/p/uF3HGNPk8wr)]
|
||||
- **<big>Fibonacci</big>** :calculate fibonacci number before n for int.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Fibonacci)]
|
||||
[[play](https://go.dev/play/p/IscseUNMuUc)]
|
||||
- **<big>Factorial</big>** : calculate x! for uint.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Factorial)]
|
||||
[[play](https://go.dev/play/p/tt6LdOK67Nx)]
|
||||
- **<big>Max</big>** : return maximum value of numbers.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Max)]
|
||||
[[play](https://go.dev/play/p/cN8DHI0rTkH)]
|
||||
- **<big>MaxBy</big>** : return the maximum value of a slice using the given comparator function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#MaxBy)]
|
||||
[[play](https://go.dev/play/p/pbe2MT-7DV2)]
|
||||
- **<big>Min</big>** : return minimum value of numbers.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Min)]
|
||||
[[play](https://go.dev/play/p/21BER_mlGUj)]
|
||||
- **<big>MinBy</big>** : return the minimum value of a slice using the given comparator function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#MinBy)]
|
||||
[[play](https://go.dev/play/p/N9qgYg_Ho6f)]
|
||||
- **<big>Percent</big>** : calculate the percentage of value to total.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Percent)]
|
||||
- **<big>RoundToFloat</big>** : round up to n decimal places for float64.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#RoundToFloat)]
|
||||
[[play](https://go.dev/play/p/ghyb528JRJL)]
|
||||
- **<big>RoundToString</big>** : round up to n decimal places for float64, return string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#RoundToString)]
|
||||
[[play](https://go.dev/play/p/kZwpBRAcllO)]
|
||||
- **<big>TruncRound</big>** : round off n decimal places for int64.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#TruncRound)]
|
||||
[[play](https://go.dev/play/p/aumarSHIGzP)]
|
||||
|
||||
### 13. Netutil package contains functions to get net information and send http request.
|
||||
|
||||
@@ -371,7 +540,6 @@ import "github.com/duke-git/lancet/v2/netutil"
|
||||
- [SendRequest](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#SendRequest)
|
||||
- [DecodeResponse](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#DecodeResponse)
|
||||
- [StructToUrlValues](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#StructToUrlValues)
|
||||
|
||||
- [HttpGet<sup>deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpGet)
|
||||
- [HttpDelete<sup>deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpDelete)
|
||||
- [HttpPost<sup>deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpPost)
|
||||
@@ -387,14 +555,30 @@ import "github.com/duke-git/lancet/v2/random"
|
||||
|
||||
#### Function list:
|
||||
|
||||
- [RandBytes](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandBytes)
|
||||
- [RandInt](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandInt)
|
||||
- [RandString](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandString)
|
||||
- [RandUpper](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandUpper)
|
||||
- [RandLower](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandLower)
|
||||
- [RandNumeral](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandNumeral)
|
||||
- [RandNumeralOrLetter](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandNumeralOrLetter)
|
||||
- [UUIdV4](https://github.com/duke-git/lancet/blob/main/docs/random.md#UUIdV4)
|
||||
- **<big>RandBytes</big>** : generate random byte slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandBytes)]
|
||||
[[play](https://go.dev/play/p/EkiLESeXf8d)]
|
||||
- **<big>RandInt</big>** : generate random int number between min and max.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandInt)]
|
||||
[[play](https://go.dev/play/p/pXyyAAI5YxD)]
|
||||
- **<big>RandString</big>** : generate random string of specified length.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandString)]
|
||||
[[play](https://go.dev/play/p/W2xvRUXA7Mi)]
|
||||
- **<big>RandUpper</big>** : generate a random upper case string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandUpper)]
|
||||
[[play](https://go.dev/play/p/29QfOh0DVuh)]
|
||||
- **<big>RandLower</big>** : generate a random lower case string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandLower)]
|
||||
[[play](https://go.dev/play/p/XJtZ471cmtI)]
|
||||
- **<big>RandNumeral</big>** : generate a random numeral string of specified length.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandNumeral)]
|
||||
[[play](https://go.dev/play/p/g4JWVpHsJcf)]
|
||||
- **<big>RandNumeralOrLetter</big>** : generate a random numeral or letter string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandNumeralOrLetter)]
|
||||
[[play](https://go.dev/play/p/19CEQvpx2jD)]
|
||||
- **<big>UUIdV4</big>** : generate a random UUID of version 4 according to RFC 4122.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random.md#UUIdV4)]
|
||||
[[play](https://go.dev/play/p/_Z9SFmr28ft)]
|
||||
|
||||
### 15. Retry package is for executing a function repeatedly until it was successful or canceled by the context.
|
||||
|
||||
@@ -404,11 +588,23 @@ import "github.com/duke-git/lancet/v2/retry"
|
||||
|
||||
#### Function list:
|
||||
|
||||
- [Context](https://github.com/duke-git/lancet/blob/main/docs/retry.md#Context)
|
||||
- [Retry](https://github.com/duke-git/lancet/blob/main/docs/retry.md#Retry)
|
||||
- [RetryFunc](https://github.com/duke-git/lancet/blob/main/docs/retry.md#RetryFunc)
|
||||
- [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)
|
||||
- **<big>Context</big>** : set retry context config option.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/retry.md#Context)]
|
||||
[[play](https://go.dev/play/p/xnAOOXv9GkS)]
|
||||
- **<big>Retry</big>** : executes the retryFunc repeatedly until it was successful or canceled by the context.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/retry.md#Retry)]
|
||||
[[play](https://go.dev/play/p/nk2XRmagfVF)]
|
||||
- **<big>RetryFunc</big>** : function that retry executes.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/retry.md#RetryFunc)]
|
||||
[[play](https://go.dev/play/p/nk2XRmagfVF)]
|
||||
- **<big>RetryDuration</big>** : set duration of retry
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/retry.md#RetryDuration)]
|
||||
[[play](https://go.dev/play/p/nk2XRmagfVF)]
|
||||
- **<big>RetryTimes</big>** : set times of retry.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/retry.md#RetryTimes)]
|
||||
[[play](https://go.dev/play/p/ssfVeU2SwLO)]
|
||||
|
||||
|
||||
|
||||
### 16. Slice contains some functions to manipulate slice.
|
||||
|
||||
@@ -418,59 +614,165 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
|
||||
#### Function list:
|
||||
|
||||
- [AppendIfAbsent](https://github.com/duke-git/lancet/blob/main/docs/slice.md#AppendIfAbsent)
|
||||
- [Contain](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Contain)
|
||||
- [ContainSubSlice](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ContainSubSlice)
|
||||
- [Chunk](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Chunk)
|
||||
- [Compact](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Compact)
|
||||
- [Concat](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Concat)
|
||||
- [Count](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Count)
|
||||
- [CountBy](https://github.com/duke-git/lancet/blob/main/docs/slice.md#CountBy)
|
||||
- [Difference](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Difference)
|
||||
- [DifferenceBy](https://github.com/duke-git/lancet/blob/main/docs/slice.md#DifferenceBy)
|
||||
- [DifferenceWith](https://github.com/duke-git/lancet/blob/main/docs/slice.md#DifferenceWith)
|
||||
- [DeleteAt](https://github.com/duke-git/lancet/blob/main/docs/slice.md#DeleteAt)
|
||||
- [Drop](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Drop)
|
||||
- [Equal](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Equal)
|
||||
- [EqualWith](https://github.com/duke-git/lancet/blob/main/docs/slice.md#EqualWith)
|
||||
- [Every](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Every)
|
||||
- [Filter](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Filter)
|
||||
- [Find](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Find)
|
||||
- [FindLast](https://github.com/duke-git/lancet/blob/main/docs/slice.md#FindLast)
|
||||
- [Flatten](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Flatten)
|
||||
- [FlattenDeep](https://github.com/duke-git/lancet/blob/main/docs/slice.md#FlattenDeep)
|
||||
- [ForEach](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ForEach)
|
||||
- [GroupBy](https://github.com/duke-git/lancet/blob/main/docs/slice.md#GroupBy)
|
||||
- [GroupWith](https://github.com/duke-git/lancet/blob/main/docs/slice.md#GroupWith)
|
||||
- [IntSlice<sup>deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/slice.md#IntSlice)
|
||||
- [InterfaceSlice<sup>deprecated</sup>](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)
|
||||
- [Merge](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Merge)
|
||||
- [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)
|
||||
- [Replace](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Replace)
|
||||
- [ReplaceAll](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ReplaceAll)
|
||||
- [Repeat](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Repeat)
|
||||
- [Shuffle](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Shuffle)
|
||||
- [Sort](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Sort)
|
||||
- [SortBy](https://github.com/duke-git/lancet/blob/main/docs/slice.md#SortBy)
|
||||
- [SortByField<sup>deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/slice.md#SortByField)
|
||||
- [Some](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Some)
|
||||
- [StringSlice<sup>deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/slice.md#StringSlice)
|
||||
- [SymmetricDifference](https://github.com/duke-git/lancet/blob/main/docs/slice.md#SymmetricDifference)
|
||||
- [ToSlice](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ToSlice)
|
||||
- [ToSlicePointer](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ToSlicePointer)
|
||||
- [Unique](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Unique)
|
||||
- [UniqueBy](https://github.com/duke-git/lancet/blob/main/docs/slice.md#UniqueBy)
|
||||
- [Union](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Union)
|
||||
- [UnionBy](https://github.com/duke-git/lancet/blob/main/docs/slice.md#UnionBy)
|
||||
- [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)
|
||||
- [KeyBy](https://github.com/duke-git/lancet/blob/main/docs/slice.md#KeyBy)
|
||||
- **<big>AppendIfAbsent</big>** : if the item is absent,append it to the slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#AppendIfAbsent)]
|
||||
[[play](https://go.dev/play/p/GNdv7Jg2Taj)]
|
||||
- **<big>Contain</big>** : check if the value is in the slice or not.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Contain)]
|
||||
[[play](https://go.dev/play/p/_454yEHcNjf)]
|
||||
- **<big>ContainSubSlice</big>** : check if the slice contain a given subslice or not.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ContainSubSlice)]
|
||||
[[play](https://go.dev/play/p/bcuQ3UT6Sev)]
|
||||
- **<big>Chunk</big>** : creates a slice of elements split into groups the length of size.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Chunk)]
|
||||
[[play](https://go.dev/play/p/b4Pou5j2L_C)]
|
||||
- **<big>Compact</big>** : creates an slice with all falsey values removed. The values false, nil, 0, and "" are falsey.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Compact)]
|
||||
[[play](https://go.dev/play/p/pO5AnxEr3TK)]
|
||||
- **<big>Concat</big>** : creates a new slice concatenating slice with any additional slices.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Concat)]
|
||||
[[play](https://go.dev/play/p/gPt-q7zr5mk)]
|
||||
- **<big>Count</big>** : returns the number of occurrences of the given item in the slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Count)]
|
||||
[[play](https://go.dev/play/p/Mj4oiEnQvRJ)]
|
||||
- **<big>CountBy</big>** : iterates over elements of slice with predicate function, returns the number of all matched elements.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#CountBy)]
|
||||
[[play](https://go.dev/play/p/tHOccTMDZCC)]
|
||||
- **<big>Difference</big>** : creates an slice of whose element in slice but not in compared slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Difference)]
|
||||
[[play](https://go.dev/play/p/VXvadzLzhDa)]
|
||||
- **<big>DifferenceBy</big>** : accepts iteratee which is invoked for each element of slice and values to generate the criterion by which they're compared.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#DifferenceBy)]
|
||||
[[play](https://go.dev/play/p/DiivgwM5OnC)]
|
||||
- **<big>DifferenceWith</big>** : accepts comparator which is invoked to compare elements of slice to values.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#DifferenceWith)]
|
||||
[[play](https://go.dev/play/p/v2U2deugKuV)]
|
||||
- **<big>DeleteAt</big>** : delete the element of slice from specific start index to end index - 1.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#DeleteAt)]
|
||||
[[play](https://go.dev/play/p/pJ-d6MUWcvK)]
|
||||
- **<big>Drop</big>** : creates a slice with `n` elements dropped from the beginning when n > 0, or `n` elements dropped from the ending when n < 0.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Drop)]
|
||||
[[play](https://go.dev/play/p/pJ-d6MUWcvK)]
|
||||
- **<big>Equal</big>** : checks if two slices are equal: the same length and all elements' order and value are equal.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Equal)]
|
||||
[[play](https://go.dev/play/p/WcRQJ37ifPa)]
|
||||
- **<big>EqualWith</big>** : checks if two slices are equal with comparator func.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#EqualWith)]
|
||||
[[play](https://go.dev/play/p/b9iygtgsHI1)]
|
||||
- **<big>Every</big>** : return true if all of the values in the slice pass the predicate function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Every)]
|
||||
[[play](https://go.dev/play/p/R8U6Sl-j8cD)]
|
||||
- **<big>Filter</big>** : iterates over elements of slice, returning an slice of all elements pass the predicate function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Filter)]
|
||||
[[play](https://go.dev/play/p/SdPna-7qK4T)]
|
||||
- **<big>Find</big>** : iterates over elements of slice, returning the first one that passes a truth test on predicate function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Find)]
|
||||
[[play](https://go.dev/play/p/CBKeBoHVLgq)]
|
||||
- **<big>FindLast</big>** : return the last item that passes a truth test on predicate function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#FindLast)]
|
||||
[[play](https://go.dev/play/p/FFDPV_j7URd)]
|
||||
- **<big>Flatten</big>** : flattens slice one level.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Flatten)]
|
||||
[[play](https://go.dev/play/p/hYa3cBEevtm)]
|
||||
- **<big>FlattenDeep</big>** : flattens slice recursive to one level.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#FlattenDeep)]
|
||||
[[play](https://go.dev/play/p/yjYNHPyCFaF)]
|
||||
- **<big>ForEach</big>** : iterates over elements of slice and invokes function for each element.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ForEach)]
|
||||
[[play](https://go.dev/play/p/DrPaa4YsHRF)]
|
||||
- **<big>GroupBy</big>** : iterate over elements of the slice, each element will be group by criteria, returns two slices.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#GroupBy)]
|
||||
[[play](https://go.dev/play/p/QVkPxzPR0iA)]
|
||||
- **<big>GroupWith</big>** : return a map composed of keys generated from the resultults of running each element of slice thru iteratee.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#GroupWith)]
|
||||
[[play](https://go.dev/play/p/ApCvMNTLO8a)]
|
||||
- **<big>IntSlice<sup>deprecated</sup></big>** : convert param to int slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#IntSlice)]
|
||||
[[play](https://go.dev/play/p/FdQXF0Vvqs-)]
|
||||
- **<big>InterfaceSlice<sup>deprecated</sup></big>** : convert param to interface slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#InterfaceSlice)]
|
||||
[[play](https://go.dev/play/p/FdQXF0Vvqs-)]
|
||||
- **<big>Intersection</big>** : creates a slice of unique elements that included by all slices.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Intersection)]
|
||||
[[play](https://go.dev/play/p/anJXfB5wq_t)]
|
||||
- **<big>InsertAt</big>** : insert the value or other slice into slice at index.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#InsertAt)]
|
||||
[[play](https://go.dev/play/p/hMLNxPEGJVE)]
|
||||
- **<big>IndexOf</big>** : returns the index at which the first occurrence of an item is found in a slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#IndexOf)]
|
||||
[[play](https://go.dev/play/p/MRN1f0FpABb)]
|
||||
- **<big>LastIndexOf</big>** : returns the index at which the last occurrence of the item is found in a slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#LastIndexOf)]
|
||||
[[play](https://go.dev/play/p/DokM4cf1IKH)]
|
||||
- **<big>Map</big>** : creates an slice of values by running each element of slice thru iteratee function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Map)]
|
||||
[[play](https://go.dev/play/p/biaTefqPquw)]
|
||||
- **<big>Merge</big>** : merge all given slices into one slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Merge)]
|
||||
[[play](https://go.dev/play/p/lbjFp784r9N)]
|
||||
- **<big>Reverse</big>** : return slice of element order is reversed to the given slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Reverse)]
|
||||
[[play](https://go.dev/play/p/8uI8f1lwNrQ)]
|
||||
- **<big>Reduce</big>** : creates an slice of values by running each element of slice thru iteratee function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Reduce)]
|
||||
[[play](https://go.dev/play/p/_RfXJJWIsIm)]
|
||||
- **<big>Replace</big>** : returns a copy of the slice with the first n non-overlapping instances of old replaced by new.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Replace)]
|
||||
[[play](https://go.dev/play/p/P5mZp7IhOFo)]
|
||||
- **<big>ReplaceAll</big>** : returns a copy of the slice with all non-overlapping instances of old replaced by new.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ReplaceAll)]
|
||||
[[play](https://go.dev/play/p/CzqXMsuYUrx)]
|
||||
- **<big>Repeat</big>** : creates a slice with length n whose elements are passed item.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Repeat)]
|
||||
[[play](https://go.dev/play/p/1CbOmtgILUU)]
|
||||
- **<big>Shuffle</big>** : shuffle the slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Shuffle)]
|
||||
[[play](https://go.dev/play/p/YHvhnWGU3Ge)]
|
||||
- **<big>Sort</big>** : sorts a slice of any ordered type(number or string).
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Sort)]
|
||||
[[play](https://go.dev/play/p/V9AVjzf_4Fk)]
|
||||
- **<big>SortBy</big>** : sorts the slice in ascending order as determined by the less function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#SortBy)]
|
||||
[[play](https://go.dev/play/p/DAhLQSZEumm)]
|
||||
- **<big>SortByField<sup>deprecated</sup></big>** : return sorted slice by specific field.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#SortByField)]
|
||||
[[play](https://go.dev/play/p/fU1prOBP9p1)]
|
||||
- **<big>Some</big>** : return true if any of the values in the list pass the predicate function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Some)]
|
||||
[[play](https://go.dev/play/p/4pO9Xf9NDGS)]
|
||||
- **<big>StringSlice<sup>deprecated</sup></big>** : convert param to slice of string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#StringSlice)]
|
||||
[[play](https://go.dev/play/p/W0TZDWCPFcI)]
|
||||
- **<big>SymmetricDifference</big>** : the symmetric difference of two slice, also known as the disjunctive union.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#h42nJX5xMln)]
|
||||
[[play](https://go.dev/play/p/1CbOmtgILUU)]
|
||||
- **<big>ToSlice</big>** : returns a slices of a variable parameter transformation.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ToSlice)]
|
||||
[[play](https://go.dev/play/p/YzbzVq5kscN)]
|
||||
- **<big>ToSlicePointer</big>** : returns a pointer to the slices of a variable parameter transformation.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ToSlicePointer)]
|
||||
[[play](https://go.dev/play/p/gx4tr6_VXSF)]
|
||||
- **<big>Unique</big>** : remove duplicate elements in slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Unique)]
|
||||
[[play](https://go.dev/play/p/AXw0R3ZTE6a)]
|
||||
- **<big>UniqueBy</big>** : call iteratee func with every item of slice, then remove duplicated.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#UniqueBy)]
|
||||
[[play](https://go.dev/play/p/UR323iZLDpv)]
|
||||
- **<big>Union</big>** : creates a slice of unique elements, in order, from all given slices.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Union)]
|
||||
[[play](https://go.dev/play/p/hfXV1iRIZOf)]
|
||||
- **<big>UnionBy</big>** : accepts iteratee which is invoked for each element of each slice, then union slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#UnionBy)]
|
||||
[[play](https://go.dev/play/p/HGKHfxKQsFi)]
|
||||
- **<big>UpdateAt</big>** : update the slice element at index.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#UpdateAt)]
|
||||
[[play](https://go.dev/play/p/f3mh2KloWVm)]
|
||||
- **<big>Without</big>** : creates a slice excluding all given items.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Without)]
|
||||
[[play](https://go.dev/play/p/bwhEXEypThg)]
|
||||
- **<big>KeyBy</big>** : converts a slice to a map based on a callback function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#KeyBy)]
|
||||
[[play](https://go.dev/play/p/uXod2LWD1Kg)]
|
||||
|
||||
### 17. Strutil package contains some functions to manipulate string.
|
||||
|
||||
@@ -480,23 +782,64 @@ import "github.com/duke-git/lancet/v2/strutil"
|
||||
|
||||
#### Function list:
|
||||
|
||||
- [After](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#After)
|
||||
- [AfterLast](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#AfterLast)
|
||||
- [Before](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Before)
|
||||
- [BeforeLast](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#BeforeLast)
|
||||
- [CamelCase](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#CamelCase)
|
||||
- [Capitalize](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Capitalize)
|
||||
- [IsString](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#IsString)
|
||||
- [KebabCase](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#KebabCase)
|
||||
- [LowerFirst](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#LowerFirst)
|
||||
- [UpperFirst](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#UpperFirst)
|
||||
- [PadEnd](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#PadEnd)
|
||||
- [PadStart](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#PadStart)
|
||||
- [Reverse](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Reverse)
|
||||
- [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)
|
||||
- **<big>After</big>** : returns the substring after the first occurrence of a specified string in the source string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#After)]
|
||||
[[play](https://go.dev/play/p/RbCOQqCDA7m)]
|
||||
- **<big>AfterLast</big>** : returns the substring after the last occurrence of a specified string in the source string. [[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#AfterLast)]
|
||||
[[play](https://go.dev/play/p/1TegARrb8Yn)]
|
||||
- **<big>Before</big>** : returns the substring before the first occurrence of a specified string in the source string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Before)]
|
||||
[[play](https://go.dev/play/p/JAWTZDS4F5w)]
|
||||
- **<big>BeforeLast</big>** : returns the substring before the last occurrence of a specified string in the source string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#BeforeLast)]
|
||||
[[play](https://go.dev/play/p/pJfXXAoG_Te)]
|
||||
- **<big>CamelCase</big>** : coverts source string to its camelCase string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#CamelCase)]
|
||||
[[play](https://go.dev/play/p/9eXP3tn2tUy)]
|
||||
- **<big>Capitalize</big>** : converts the first character of source string to upper case and the remaining to lower case.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Capitalize)]
|
||||
[[play](https://go.dev/play/p/2OAjgbmAqHZ)]
|
||||
- **<big>IsString</big>** : checks if the parameter value data type is string or not.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#IsString)]
|
||||
[[play](https://go.dev/play/p/IOgq7oF9ERm)]
|
||||
- **<big>KebabCase</big>** : coverts string to kebab-case string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#KebabCase)]
|
||||
[[play](https://go.dev/play/p/dcZM9Oahw-Y)]
|
||||
- **<big>UpperKebabCase</big>** : coverts string to upper KEBAB-CASE string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#UpperKebabCase)]
|
||||
[[play](https://go.dev/play/p/zDyKNneyQXk)]
|
||||
- **<big>LowerFirst</big>** : converts the first character of string to lower case.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#LowerFirst)]
|
||||
[[play](https://go.dev/play/p/CbzAyZmtJwL)]
|
||||
- **<big>UpperFirst</big>** : converts the first character of string to upper case.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#UpperFirst)]
|
||||
[[play](https://go.dev/play/p/sBbBxRbs8MM)]
|
||||
- **<big>PadEnd</big>** : pads string with given characters on the right side if it's shorter than limit size. Padding characters are truncated if they exceed size.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#PadEnd)]
|
||||
[[play](https://go.dev/play/p/9xP8rN0vz--)]
|
||||
- **<big>PadStart</big>** : pads string with given characters on the left side if it's shorter than limit size. Padding characters are truncated if they exceed size.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#PadStart)]
|
||||
[[play](https://go.dev/play/p/xpTfzArDfvT)]
|
||||
- **<big>Reverse</big>** : returns string whose char order is reversed to the given string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Reverse)]
|
||||
[[play](https://go.dev/play/p/adfwalJiecD)]
|
||||
- **<big>SnakeCase</big>** : coverts string to snake_case string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#SnakeCase)]
|
||||
[[play](https://go.dev/play/p/tgzQG11qBuN)]
|
||||
- **<big>UpperSnakeCase</big>** : coverts string to upper SNAKE_CASE string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#UpperSnakeCase)]
|
||||
[[play](https://go.dev/play/p/4COPHpnLx38)]
|
||||
- **<big>SplitEx</big>** : split a given string which can control the result slice contains empty string or not.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#SplitEx)]
|
||||
[[play](https://go.dev/play/p/Us-ySSbWh-3)]
|
||||
- **<big>Substring</big>** : returns a substring of the specified length starting at the specified offset position.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Substring)]
|
||||
- **<big>Wrap</big>** : wrap a string with given string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Wrap)]
|
||||
[[play](https://go.dev/play/p/KoZOlZDDt9y)]
|
||||
- **<big>Unwrap</big>** : unwrap a given string from anther string. will change source string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Unwrap)]
|
||||
[[play](https://go.dev/play/p/Ec2q4BzCpG-)]
|
||||
|
||||
### 19. System package contain some functions about os, runtime, shell command.
|
||||
|
||||
@@ -506,15 +849,33 @@ import "github.com/duke-git/lancet/v2/system"
|
||||
|
||||
#### Function list:
|
||||
|
||||
- [IsWindows](https://github.com/duke-git/lancet/blob/main/docs/system.md#IsWindows)
|
||||
- [IsLinux](https://github.com/duke-git/lancet/blob/main/docs/system.md#IsLinux)
|
||||
- [IsMac](https://github.com/duke-git/lancet/blob/main/docs/system.md#IsMac)
|
||||
- [GetOsEnv](https://github.com/duke-git/lancet/blob/main/docs/system.md#GetOsEnv)
|
||||
- [SetOsEnv](https://github.com/duke-git/lancet/blob/main/docs/system.md#SetOsEnv)
|
||||
- [RemoveOsEnv](https://github.com/duke-git/lancet/blob/main/docs/system.md#RemoveOsEnv)
|
||||
- [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)
|
||||
- [GetOsBits](https://github.com/duke-git/lancet/blob/main/docs/system.md#GetOsBits)
|
||||
- **<big>IsWindows</big>** : check if current os is windows.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/system.md#IsWindows)]
|
||||
[[play](https://go.dev/play/p/XzJULbzmf9m)]
|
||||
- **<big>IsLinux</big>** : check if current os is linux.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/system.md#IsLinux)]
|
||||
[[play](https://go.dev/play/p/zIflQgZNuxD)]
|
||||
- **<big>IsMac</big>** : check if current os is macos.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/system.md#IsMac)]
|
||||
[[play](https://go.dev/play/p/Mg4Hjtyq7Zc)]
|
||||
- **<big>GetOsEnv</big>** : get the value of the environment variable named by the key.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/system.md#GetOsEnv)]
|
||||
[[play](https://go.dev/play/p/D88OYVCyjO-)]
|
||||
- **<big>SetOsEnv</big>** : set the value of the environment variable named by the key.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/system.md#SetOsEnv)]
|
||||
[[play](https://go.dev/play/p/D88OYVCyjO-)]
|
||||
- **<big>RemoveOsEnv</big>** : remove a single environment variable.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/system.md#RemoveOsEnv)]
|
||||
[[play](https://go.dev/play/p/fqyq4b3xUFQ)]
|
||||
- **<big>CompareOsEnv</big>** : get env named by the key and compare it with passed env.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/system.md#CompareOsEnv)]
|
||||
[[play](https://go.dev/play/p/BciHrKYOHbp)]
|
||||
- **<big>ExecCommand</big>** : execute command, return the stdout and stderr string of command, and error if error occurs.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/system.md#ExecCommand)]
|
||||
[[play](https://go.dev/play/p/n-2fLyZef-4)]
|
||||
- **<big>GetOsBits</big>** : return current os bits (32 or 64).
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/system.md#GetOsBits)]
|
||||
[[play](https://go.dev/play/p/ml-_XH3gJbW)]
|
||||
|
||||
### 19. Validator package contains some functions for data validation.
|
||||
|
||||
@@ -524,33 +885,90 @@ import "github.com/duke-git/lancet/v2/validator"
|
||||
|
||||
#### Function list:
|
||||
|
||||
- [ContainChinese](https://github.com/duke-git/lancet/blob/main/docs/validator.md#ContainChinese)
|
||||
- [ContainLetter](https://github.com/duke-git/lancet/blob/main/docs/validator.md#ContainLetter)
|
||||
- [ContainLower](https://github.com/duke-git/lancet/blob/main/docs/validator.md#ContainLower)
|
||||
- [ContainUpper](https://github.com/duke-git/lancet/blob/main/docs/validator.md#ContainUpper)
|
||||
- [IsAlpha](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsAlpha)
|
||||
- [IsAllUpper](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsAllUpper)
|
||||
- [IsAllLower](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsAllLower)
|
||||
- [IsBase64](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsBase64)
|
||||
- [IsChineseMobile](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsChineseMobile)
|
||||
- [IsChineseIdNum](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsChineseIdNum)
|
||||
- [IsChinesePhone](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsChinesePhone)
|
||||
- [IsCreditCard](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsCreditCard)
|
||||
- [IsDns](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsDns)
|
||||
- [IsEmail](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsEmail)
|
||||
- [IsEmptyString](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsEmptyString)
|
||||
- [IsFloatStr](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsFloatStr)
|
||||
- [IsNumberStr](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsNumberStr)
|
||||
- [IsJSON](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsJSON)
|
||||
- [IsRegexMatch](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsRegexMatch)
|
||||
- [IsIntStr](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsIntStr)
|
||||
- [IsIp](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsIp)
|
||||
- [IsIpV4](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsIpV4)
|
||||
- [IsIpV6](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsIpV6)
|
||||
- [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)
|
||||
- [IsZeroValue](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsZeroValue)
|
||||
- **<big>ContainChinese</big>** : check if the string contain mandarin chinese.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#ContainChinese)]
|
||||
[[play](https://go.dev/play/p/7DpU0uElYeM)]
|
||||
- **<big>ContainLetter</big>** : check if the string contain at least one letter.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#ContainLetter)]
|
||||
[[play](https://go.dev/play/p/lqFD04Yyewp)]
|
||||
- **<big>ContainLower</big>** : check if the string contain at least one lower case letter a-z.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#ContainLower)]
|
||||
[[play](https://go.dev/play/p/Srqi1ItvnAA)]
|
||||
- **<big>ContainUpper</big>** : check if the string contain at least one upper case letter A-Z.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#ContainUpper)]
|
||||
[[play](https://go.dev/play/p/CmWeBEk27-z)]
|
||||
- **<big>IsAlpha</big>** : checks if the string contains only letters (a-zA-Z).
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsAlpha)]
|
||||
[[play](https://go.dev/play/p/7Q5sGOz2izQ)]
|
||||
- **<big>IsAllUpper</big>** : check if the string is all upper case letters A-Z.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsAllUpper)]
|
||||
[[play](https://go.dev/play/p/ZHctgeK1n4Z)]
|
||||
- **<big>IsAllLower</big>** : check if the string is all lower case letters a-z.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsAllLower)]
|
||||
[[play](https://go.dev/play/p/GjqCnOfV6cM)]
|
||||
- **<big>IsBase64</big>** : check if the string is base64 string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsBase64)]
|
||||
[[play](https://go.dev/play/p/sWHEySAt6hl)]
|
||||
- **<big>IsChineseMobile</big>** : check if the string is chinese mobile number.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsChineseMobile)]
|
||||
[[play](https://go.dev/play/p/GPYUlGTOqe3)]
|
||||
- **<big>IsChineseIdNum</big>** : check if the string is chinese id card.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsChineseIdNum)]
|
||||
[[play](https://go.dev/play/p/d8EWhl2UGDF)]
|
||||
- **<big>IsChinesePhone</big>** : check if the string is chinese phone number.(xxx-xxxxxxxx or xxxx-xxxxxxx.)
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsChinesePhone)]
|
||||
[[play](https://go.dev/play/p/RUD_-7YZJ3I)]
|
||||
- **<big>IsCreditCard</big>** : check if the string is credit card.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsCreditCard)]
|
||||
[[play](https://go.dev/play/p/sNwwL6B0-v4)]
|
||||
- **<big>IsDns</big>** : check if the string is dns.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsDns)]
|
||||
[[play](https://go.dev/play/p/jlYApVLLGTZ)]
|
||||
- **<big>IsEmail</big>** : check if the string is a email address.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsEmail)]
|
||||
[[play](https://go.dev/play/p/Os9VaFlT33G)]
|
||||
- **<big>IsEmptyString</big>** : check if the string is empty.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsEmptyString)]
|
||||
[[play](https://go.dev/play/p/dpzgUjFnBCX)]
|
||||
- **<big>IsFloatStr</big>** : check if the string can convert to a float.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#LOYwS_Oyl7U)]
|
||||
[[play](https://go.dev/play/p/LOYwS_Oyl7U)]
|
||||
- **<big>IsNumberStr</big>** : check if the string can convert to a number.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsNumberStr)]
|
||||
[[play](https://go.dev/play/p/LzaKocSV79u)]
|
||||
- **<big>IsJSON</big>** : check if the string is valid JSON.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsJSON)]
|
||||
[[play](https://go.dev/play/p/sRS6c4K8jGk)]
|
||||
- **<big>IsRegexMatch</big>** : check if the string match the regexp.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsRegexMatch)]
|
||||
[[play](https://go.dev/play/p/z_XeZo_litG)]
|
||||
- **<big>IsIntStr</big>** : check if the string can convert to a integer.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsIntStr)]
|
||||
[[play](https://go.dev/play/p/jQRtFv-a0Rk)]
|
||||
- **<big>IsIp</big>** : check if the string is ip.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsIp)]
|
||||
[[play](https://go.dev/play/p/FgcplDvmxoD)]
|
||||
- **<big>IsIpV4</big>** : check if the string is ipv4.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsIpV4)]
|
||||
[[play](https://go.dev/play/p/zBGT99EjaIu)]
|
||||
- **<big>IsIpV6</big>** : check if the string is ipv6.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsIpV6)]
|
||||
[[play](https://go.dev/play/p/AHA0r0AzIdC)]
|
||||
- **<big>IsStrongPassword</big>** : check if the string is strong password.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsStrongPassword)]
|
||||
[[play](https://go.dev/play/p/QHdVcSQ3uDg)]
|
||||
- **<big>IsUrl</big>** : check if the string is url.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsUrl)]
|
||||
[[play](https://go.dev/play/p/pbJGa7F98Ka)]
|
||||
- **<big>IsWeakPassword</big>** : check if the string is weak password.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsWeakPassword)]
|
||||
[[play](https://go.dev/play/p/wqakscZH5gH)]
|
||||
- **<big>IsZeroValue</big>** : check if value is a zero value.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsZeroValue)]
|
||||
[[play](https://go.dev/play/p/UMrwaDCi_t4)]
|
||||
- **<big>IsGBK</big>** : check if data encoding is gbk.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsGBK)]
|
||||
[[play](https://go.dev/play/p/E2nt3unlmzP)]
|
||||
|
||||
### 20. xerror package implements helpers for errors.
|
||||
|
||||
|
||||
871
README_zh-CN.md
871
README_zh-CN.md
File diff suppressed because it is too large
Load Diff
@@ -26,7 +26,7 @@ type LRUCache[K comparable, V any] struct {
|
||||
length int
|
||||
}
|
||||
|
||||
// NewLRUCache return a LRUCache pointer
|
||||
// NewLRUCache creates a LRUCache pointer instance.
|
||||
func NewLRUCache[K comparable, V any](capacity int) *LRUCache[K, V] {
|
||||
return &LRUCache[K, V]{
|
||||
cache: make(map[K]*lruNode[K, V], capacity),
|
||||
@@ -37,7 +37,8 @@ func NewLRUCache[K comparable, V any](capacity int) *LRUCache[K, V] {
|
||||
}
|
||||
}
|
||||
|
||||
// Get value of key from lru cache
|
||||
// Get value of key from lru cache.
|
||||
// Play: https://go.dev/play/p/iUynEfOP8G0
|
||||
func (l *LRUCache[K, V]) Get(key K) (V, bool) {
|
||||
var value V
|
||||
|
||||
@@ -50,7 +51,8 @@ func (l *LRUCache[K, V]) Get(key K) (V, bool) {
|
||||
return value, false
|
||||
}
|
||||
|
||||
// Put value of key into lru cache
|
||||
// Put value of key into lru cache.
|
||||
// Play: https://go.dev/play/p/iUynEfOP8G0
|
||||
func (l *LRUCache[K, V]) Put(key K, value V) {
|
||||
node, ok := l.cache[key]
|
||||
if !ok {
|
||||
@@ -69,6 +71,23 @@ func (l *LRUCache[K, V]) Put(key K, value V) {
|
||||
l.length = len(l.cache)
|
||||
}
|
||||
|
||||
// Delete item from lru cache.
|
||||
func (l *LRUCache[K, V]) Delete(key K) bool {
|
||||
node, ok := l.cache[key]
|
||||
if ok {
|
||||
key := l.deleteNode(node)
|
||||
delete(l.cache, key)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Len returns the number of items in the cache.
|
||||
func (l *LRUCache[K, V]) Len() int {
|
||||
return l.length
|
||||
}
|
||||
|
||||
func (l *LRUCache[K, V]) addNode(node *lruNode[K, V]) {
|
||||
if l.tail != nil {
|
||||
l.tail.next = node
|
||||
79
algorithm/lrucache_example_test.go
Normal file
79
algorithm/lrucache_example_test.go
Normal file
@@ -0,0 +1,79 @@
|
||||
package algorithm
|
||||
|
||||
import "fmt"
|
||||
|
||||
func ExampleLRUCache_Put() {
|
||||
cache := NewLRUCache[int, int](2)
|
||||
|
||||
cache.Put(1, 1)
|
||||
cache.Put(2, 2)
|
||||
|
||||
result1, ok1 := cache.Get(1)
|
||||
result2, ok2 := cache.Get(2)
|
||||
result3, ok3 := cache.Get(3)
|
||||
|
||||
fmt.Println(result1, ok1)
|
||||
fmt.Println(result2, ok2)
|
||||
fmt.Println(result3, ok3)
|
||||
|
||||
// Output:
|
||||
// 1 true
|
||||
// 2 true
|
||||
// 0 false
|
||||
}
|
||||
|
||||
func ExampleLRUCache_Get() {
|
||||
cache := NewLRUCache[int, int](2)
|
||||
|
||||
cache.Put(1, 1)
|
||||
cache.Put(2, 2)
|
||||
|
||||
result1, ok1 := cache.Get(1)
|
||||
result2, ok2 := cache.Get(2)
|
||||
result3, ok3 := cache.Get(3)
|
||||
|
||||
fmt.Println(result1, ok1)
|
||||
fmt.Println(result2, ok2)
|
||||
fmt.Println(result3, ok3)
|
||||
|
||||
// Output:
|
||||
// 1 true
|
||||
// 2 true
|
||||
// 0 false
|
||||
}
|
||||
|
||||
func ExampleLRUCache_Delete() {
|
||||
cache := NewLRUCache[int, int](2)
|
||||
|
||||
cache.Put(1, 1)
|
||||
cache.Put(2, 2)
|
||||
|
||||
result1, ok1 := cache.Get(1)
|
||||
|
||||
ok2 := cache.Delete(2)
|
||||
|
||||
_, ok3 := cache.Get(2)
|
||||
|
||||
fmt.Println(result1, ok1)
|
||||
fmt.Println(ok2)
|
||||
fmt.Println(ok3)
|
||||
|
||||
// Output:
|
||||
// 1 true
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleLRUCache_Len() {
|
||||
cache := NewLRUCache[int, int](2)
|
||||
|
||||
cache.Put(1, 1)
|
||||
cache.Put(2, 2)
|
||||
|
||||
result := cache.Len()
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 2
|
||||
}
|
||||
@@ -9,13 +9,13 @@ import (
|
||||
func TestLRUCache(t *testing.T) {
|
||||
asssert := internal.NewAssert(t, "TestLRUCache")
|
||||
|
||||
cache := NewLRUCache[int, int](2)
|
||||
cache := NewLRUCache[int, int](3)
|
||||
|
||||
cache.Put(1, 1)
|
||||
cache.Put(2, 2)
|
||||
cache.Put(3, 3)
|
||||
|
||||
_, ok := cache.Get(0)
|
||||
asssert.Equal(false, ok)
|
||||
asssert.Equal(3, cache.Len())
|
||||
|
||||
v, ok := cache.Get(1)
|
||||
asssert.Equal(true, ok)
|
||||
@@ -25,12 +25,9 @@ func TestLRUCache(t *testing.T) {
|
||||
asssert.Equal(true, ok)
|
||||
asssert.Equal(2, v)
|
||||
|
||||
cache.Put(3, 3)
|
||||
v, ok = cache.Get(1)
|
||||
asssert.Equal(false, ok)
|
||||
asssert.NotEqual(1, v)
|
||||
|
||||
v, ok = cache.Get(3)
|
||||
ok = cache.Delete(2)
|
||||
asssert.Equal(true, ok)
|
||||
asssert.Equal(3, v)
|
||||
|
||||
_, ok = cache.Get(2)
|
||||
asssert.Equal(false, ok)
|
||||
}
|
||||
@@ -1,26 +1,27 @@
|
||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package algorithm contain some basic algorithm functions. eg. sort, search, list, linklist, stack, queue, tree, graph. TODO
|
||||
// Package algorithm contain some basic algorithm functions. eg. sort, search, list, linklist, stack, queue, tree, graph.
|
||||
package algorithm
|
||||
|
||||
import "github.com/duke-git/lancet/v2/lancetconstraints"
|
||||
|
||||
// Search algorithms see https://github.com/TheAlgorithms/Go/tree/master/search
|
||||
|
||||
// LinearSearch Simple linear search algorithm that iterates over all elements of an slice
|
||||
// If a target is found, the index of the target is returned. Else the function return -1
|
||||
func LinearSearch[T any](slice []T, target T, comparator lancetconstraints.Comparator) int {
|
||||
// LinearSearch return the index of target in slice base on equal function.
|
||||
// If not found return -1
|
||||
func LinearSearch[T any](slice []T, target T, equal func(a, b T) bool) int {
|
||||
for i, v := range slice {
|
||||
if comparator.Compare(v, target) == 0 {
|
||||
if equal(v, target) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// BinarySearch search for target within a sorted slice, recursive call itself.
|
||||
// If a target is found, the index of the target is returned. Else the function return -1
|
||||
// BinarySearch return the index of target within a sorted slice, use binary search (recursive call itself).
|
||||
// If not found return -1.
|
||||
// Play: https://go.dev/play/p/t6MeGiUSN47
|
||||
func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int {
|
||||
if highIndex < lowIndex || len(sortedSlice) == 0 {
|
||||
return -1
|
||||
@@ -39,8 +40,9 @@ func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, com
|
||||
return midIndex
|
||||
}
|
||||
|
||||
// BinaryIterativeSearch search for target within a sorted slice.
|
||||
// If a target is found, the index of the target is returned. Else the function return -1
|
||||
// BinaryIterativeSearch return the index of target within a sorted slice, use binary search (no recursive).
|
||||
// If not found return -1.
|
||||
// Play: https://go.dev/play/p/Anozfr8ZLH3
|
||||
func BinaryIterativeSearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int {
|
||||
startIndex := lowIndex
|
||||
endIndex := highIndex
|
||||
|
||||
51
algorithm/search_example_test.go
Normal file
51
algorithm/search_example_test.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package algorithm
|
||||
|
||||
import "fmt"
|
||||
|
||||
func ExampleLinearSearch() {
|
||||
numbers := []int{3, 4, 5, 3, 2, 1}
|
||||
|
||||
equalFunc := func(a, b int) bool {
|
||||
return a == b
|
||||
}
|
||||
|
||||
result1 := LinearSearch(numbers, 3, equalFunc)
|
||||
result2 := LinearSearch(numbers, 6, equalFunc)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
// -1
|
||||
}
|
||||
|
||||
func ExampleBinarySearch() {
|
||||
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
comparator := &intComparator{}
|
||||
|
||||
result1 := BinarySearch(numbers, 5, 0, len(numbers)-1, comparator)
|
||||
result2 := BinarySearch(numbers, 9, 0, len(numbers)-1, comparator)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 4
|
||||
// -1
|
||||
}
|
||||
|
||||
func ExampleBinaryIterativeSearch() {
|
||||
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
comparator := &intComparator{}
|
||||
|
||||
result1 := BinaryIterativeSearch(numbers, 5, 0, len(numbers)-1, comparator)
|
||||
result2 := BinaryIterativeSearch(numbers, 9, 0, len(numbers)-1, comparator)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 4
|
||||
// -1
|
||||
}
|
||||
@@ -6,20 +6,24 @@ import (
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
var sortedNumbers = []int{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
|
||||
func TestLinearSearch(t *testing.T) {
|
||||
asssert := internal.NewAssert(t, "TestLinearSearch")
|
||||
|
||||
comparator := &intComparator{}
|
||||
asssert.Equal(4, LinearSearch(sortedNumbers, 5, comparator))
|
||||
asssert.Equal(-1, LinearSearch(sortedNumbers, 9, comparator))
|
||||
numbers := []int{3, 4, 5, 3, 2, 1}
|
||||
equalFunc := func(a, b int) bool {
|
||||
return a == b
|
||||
}
|
||||
|
||||
asssert.Equal(0, LinearSearch(numbers, 3, equalFunc))
|
||||
asssert.Equal(-1, LinearSearch(numbers, 6, equalFunc))
|
||||
}
|
||||
|
||||
func TestBinarySearch(t *testing.T) {
|
||||
asssert := internal.NewAssert(t, "TestBinarySearch")
|
||||
|
||||
sortedNumbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
comparator := &intComparator{}
|
||||
|
||||
asssert.Equal(4, BinarySearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator))
|
||||
asssert.Equal(-1, BinarySearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator))
|
||||
}
|
||||
@@ -27,7 +31,9 @@ func TestBinarySearch(t *testing.T) {
|
||||
func TestBinaryIterativeSearch(t *testing.T) {
|
||||
asssert := internal.NewAssert(t, "TestBinaryIterativeSearch")
|
||||
|
||||
sortedNumbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
comparator := &intComparator{}
|
||||
|
||||
asssert.Equal(4, BinaryIterativeSearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator))
|
||||
asssert.Equal(-1, BinaryIterativeSearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator))
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package algorithm contain some basic algorithm functions. eg. sort, search
|
||||
package algorithm
|
||||
|
||||
import "github.com/duke-git/lancet/v2/lancetconstraints"
|
||||
|
||||
// BubbleSort use bubble to sort slice.
|
||||
// BubbleSort applys the bubble sort algorithm to sort the collection, will change the original collection data.
|
||||
// Play: https://go.dev/play/p/GNdv7Jg2Taj
|
||||
func BubbleSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
for i := 0; i < len(slice); i++ {
|
||||
for j := 0; j < len(slice)-1-i; j++ {
|
||||
@@ -18,7 +18,8 @@ func BubbleSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
}
|
||||
}
|
||||
|
||||
// InsertionSort use insertion to sort slice.
|
||||
// InsertionSort applys the insertion sort algorithm to sort the collection, will change the original collection data.
|
||||
// Play: https://go.dev/play/p/G5LJiWgJJW6
|
||||
func InsertionSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
for i := 0; i < len(slice); i++ {
|
||||
for j := i; j > 0; j-- {
|
||||
@@ -32,7 +33,8 @@ func InsertionSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
}
|
||||
}
|
||||
|
||||
// SelectionSort use selection to sort slice.
|
||||
// SelectionSort applys the selection sort algorithm to sort the collection, will change the original collection data.
|
||||
// Play: https://go.dev/play/p/oXovbkekayS
|
||||
func SelectionSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
for i := 0; i < len(slice); i++ {
|
||||
min := i
|
||||
@@ -45,7 +47,8 @@ func SelectionSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
}
|
||||
}
|
||||
|
||||
// ShellSort shell sort slice.
|
||||
// ShellSort applys the shell sort algorithm to sort the collection, will change the original collection data.
|
||||
// Play: https://go.dev/play/p/3ibkszpJEu3
|
||||
func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
size := len(slice)
|
||||
|
||||
@@ -64,7 +67,8 @@ func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
}
|
||||
}
|
||||
|
||||
// QuickSort quick sorting for slice, lowIndex is 0 and highIndex is len(slice)-1
|
||||
// QuickSort quick sorting for slice, lowIndex is 0 and highIndex is len(slice)-1.
|
||||
// Play: https://go.dev/play/p/7Y7c1Elk3ax
|
||||
func QuickSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
quickSort(slice, 0, len(slice)-1, comparator)
|
||||
}
|
||||
@@ -93,7 +97,8 @@ func partition[T any](slice []T, lowIndex, highIndex int, comparator lancetconst
|
||||
return i
|
||||
}
|
||||
|
||||
// HeapSort use heap to sort slice
|
||||
// HeapSort applys the heap sort algorithm to sort the collection, will change the original collection data.
|
||||
// Play: https://go.dev/play/p/u6Iwa1VZS_f
|
||||
func HeapSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
size := len(slice)
|
||||
|
||||
@@ -126,7 +131,8 @@ func sift[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraint
|
||||
slice[i] = temp
|
||||
}
|
||||
|
||||
// MergeSort merge sorting for slice
|
||||
// MergeSort applys the merge sort algorithm to sort the collection, will change the original collection data.
|
||||
// Play: https://go.dev/play/p/ydinn9YzUJn
|
||||
func MergeSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
mergeSort(slice, 0, len(slice)-1, comparator)
|
||||
}
|
||||
@@ -167,7 +173,8 @@ func merge[T any](slice []T, lowIndex, midIndex, highIndex int, comparator lance
|
||||
}
|
||||
}
|
||||
|
||||
// CountSort use count sorting for slice
|
||||
// CountSort applys the count sort algorithm to sort the collection, don't change the original collection data.
|
||||
// Play: https://go.dev/play/p/tB-Umgm0DrP
|
||||
func CountSort[T any](slice []T, comparator lancetconstraints.Comparator) []T {
|
||||
size := len(slice)
|
||||
out := make([]T, size)
|
||||
|
||||
93
algorithm/sort_example_test.go
Normal file
93
algorithm/sort_example_test.go
Normal file
@@ -0,0 +1,93 @@
|
||||
package algorithm
|
||||
|
||||
import "fmt"
|
||||
|
||||
func ExampleBubbleSort() {
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
|
||||
BubbleSort(numbers, comparator)
|
||||
|
||||
fmt.Println(numbers)
|
||||
// Output:
|
||||
// [1 2 3 4 5 6]
|
||||
}
|
||||
|
||||
func ExampleCountSort() {
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
|
||||
sortedNumber := CountSort(numbers, comparator)
|
||||
|
||||
fmt.Println(numbers)
|
||||
fmt.Println(sortedNumber)
|
||||
// Output:
|
||||
// [2 1 5 3 6 4]
|
||||
// [1 2 3 4 5 6]
|
||||
}
|
||||
|
||||
func ExampleHeapSort() {
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
|
||||
HeapSort(numbers, comparator)
|
||||
|
||||
fmt.Println(numbers)
|
||||
// Output:
|
||||
// [1 2 3 4 5 6]
|
||||
}
|
||||
|
||||
func ExampleMergeSort() {
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
|
||||
MergeSort(numbers, comparator)
|
||||
|
||||
fmt.Println(numbers)
|
||||
// Output:
|
||||
// [1 2 3 4 5 6]
|
||||
}
|
||||
|
||||
func ExampleInsertionSort() {
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
|
||||
InsertionSort(numbers, comparator)
|
||||
|
||||
fmt.Println(numbers)
|
||||
// Output:
|
||||
// [1 2 3 4 5 6]
|
||||
}
|
||||
|
||||
func ExampleSelectionSort() {
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
|
||||
SelectionSort(numbers, comparator)
|
||||
|
||||
fmt.Println(numbers)
|
||||
// Output:
|
||||
// [1 2 3 4 5 6]
|
||||
}
|
||||
|
||||
func ExampleShellSort() {
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
|
||||
ShellSort(numbers, comparator)
|
||||
|
||||
fmt.Println(numbers)
|
||||
// Output:
|
||||
// [1 2 3 4 5 6]
|
||||
}
|
||||
|
||||
func ExampleQuickSort() {
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
|
||||
QuickSort(numbers, comparator)
|
||||
|
||||
fmt.Println(numbers)
|
||||
// Output:
|
||||
// [1 2 3 4 5 6]
|
||||
}
|
||||
@@ -66,6 +66,7 @@ func TestBubbleSortForStructSlice(t *testing.T) {
|
||||
|
||||
func TestBubbleSortForIntSlice(t *testing.T) {
|
||||
asssert := internal.NewAssert(t, "TestBubbleSortForIntSlice")
|
||||
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
BubbleSort(numbers, comparator)
|
||||
|
||||
@@ -11,17 +11,18 @@ import (
|
||||
|
||||
// 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 {
|
||||
type Channel[T any] struct {
|
||||
}
|
||||
|
||||
// NewChannel return a Channel instance
|
||||
func NewChannel() *Channel {
|
||||
return &Channel{}
|
||||
func NewChannel[T any]() *Channel[T] {
|
||||
return &Channel[T]{}
|
||||
}
|
||||
|
||||
// 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)
|
||||
// Generate creates channel, then put values into the channel.
|
||||
// Play:
|
||||
func (c *Channel[T]) Generate(ctx context.Context, values ...T) <-chan T {
|
||||
dataStream := make(chan T)
|
||||
|
||||
go func() {
|
||||
defer close(dataStream)
|
||||
@@ -38,9 +39,10 @@ func (c *Channel) Generate(ctx context.Context, values ...any) <-chan any {
|
||||
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)
|
||||
// Repeat create channel, put values into the channel repeatly until cancel the context.
|
||||
// Play:
|
||||
func (c *Channel[T]) Repeat(ctx context.Context, values ...T) <-chan T {
|
||||
dataStream := make(chan T)
|
||||
|
||||
go func() {
|
||||
defer close(dataStream)
|
||||
@@ -57,10 +59,11 @@ func (c *Channel) Repeat(ctx context.Context, values ...any) <-chan any {
|
||||
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)
|
||||
// RepeatFn create a channel, excutes fn repeatly, and put the result into the channel
|
||||
// until close context.
|
||||
// Play:
|
||||
func (c *Channel[T]) RepeatFn(ctx context.Context, fn func() T) <-chan T {
|
||||
dataStream := make(chan T)
|
||||
|
||||
go func() {
|
||||
defer close(dataStream)
|
||||
@@ -75,9 +78,10 @@ func (c *Channel) RepeatFn(ctx context.Context, fn func() any) <-chan any {
|
||||
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)
|
||||
// Take create a channel whose values are taken from another channel with limit number.
|
||||
// Play:
|
||||
func (c *Channel[T]) Take(ctx context.Context, valueStream <-chan T, number int) <-chan T {
|
||||
takeStream := make(chan T)
|
||||
|
||||
go func() {
|
||||
defer close(takeStream)
|
||||
@@ -94,16 +98,17 @@ func (c *Channel) Take(ctx context.Context, valueStream <-chan any, number int)
|
||||
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)
|
||||
// FanIn merge multiple channels into one channel.
|
||||
// Play:
|
||||
func (c *Channel[T]) FanIn(ctx context.Context, channels ...<-chan T) <-chan T {
|
||||
out := make(chan T)
|
||||
|
||||
go func() {
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(len(channels))
|
||||
|
||||
for _, c := range channels {
|
||||
go func(c <-chan any) {
|
||||
go func(c <-chan T) {
|
||||
defer wg.Done()
|
||||
for v := range c {
|
||||
select {
|
||||
@@ -121,10 +126,11 @@ func (c *Channel) FanIn(ctx context.Context, channels ...<-chan any) <-chan any
|
||||
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)
|
||||
// Tee split one chanel into two channels, until cancel the context.
|
||||
// Play:
|
||||
func (c *Channel[T]) Tee(ctx context.Context, in <-chan T) (<-chan T, <-chan T) {
|
||||
out1 := make(chan T)
|
||||
out2 := make(chan T)
|
||||
|
||||
go func() {
|
||||
defer close(out1)
|
||||
@@ -147,18 +153,19 @@ func (c *Channel) Tee(ctx context.Context, in <-chan any) (<-chan any, <-chan an
|
||||
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)
|
||||
// Bridge link multiply channels into one channel.
|
||||
// Play:
|
||||
func (c *Channel[T]) Bridge(ctx context.Context, chanStream <-chan <-chan T) <-chan T {
|
||||
valStream := make(chan T)
|
||||
|
||||
go func() {
|
||||
defer close(valStream)
|
||||
|
||||
for {
|
||||
var stream <-chan any
|
||||
var stream <-chan T
|
||||
select {
|
||||
case maybeStream, ok := <-chanStream:
|
||||
if ok == false {
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
stream = maybeStream
|
||||
@@ -178,8 +185,9 @@ func (c *Channel) Bridge(ctx context.Context, chanStream <-chan <-chan any) <-ch
|
||||
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 {
|
||||
// Or read one or more channels into one channel, will close when any readin channel is closed.
|
||||
// Play:
|
||||
func (c *Channel[T]) Or(channels ...<-chan T) <-chan T {
|
||||
switch len(channels) {
|
||||
case 0:
|
||||
return nil
|
||||
@@ -187,7 +195,7 @@ func (c *Channel) Or(channels ...<-chan any) <-chan any {
|
||||
return channels[0]
|
||||
}
|
||||
|
||||
orDone := make(chan any)
|
||||
orDone := make(chan T)
|
||||
|
||||
go func() {
|
||||
defer close(orDone)
|
||||
@@ -199,17 +207,12 @@ func (c *Channel) Or(channels ...<-chan any) <-chan any {
|
||||
case <-channels[1]:
|
||||
}
|
||||
default:
|
||||
m := len(channels) / 2
|
||||
select {
|
||||
case <-c.Or(channels[:m]...):
|
||||
case <-c.Or(channels[m:]...):
|
||||
case <-channels[0]:
|
||||
case <-channels[1]:
|
||||
case <-channels[2]:
|
||||
case <-c.Or(append(channels[3:], orDone)...):
|
||||
}
|
||||
// select {
|
||||
// case <-channels[0]:
|
||||
// case <-channels[1]:
|
||||
// case <-channels[2]:
|
||||
// case <-c.Or(append(channels[3:], orDone)...):
|
||||
// }
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -217,8 +220,9 @@ func (c *Channel) Or(channels ...<-chan any) <-chan any {
|
||||
}
|
||||
|
||||
// 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)
|
||||
// Play:
|
||||
func (c *Channel[T]) OrDone(ctx context.Context, channel <-chan T) <-chan T {
|
||||
valStream := make(chan T)
|
||||
|
||||
go func() {
|
||||
defer close(valStream)
|
||||
|
||||
196
concurrency/channel_example_test.go
Normal file
196
concurrency/channel_example_test.go
Normal file
@@ -0,0 +1,196 @@
|
||||
package concurrency
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func ExampleChannel_Generate() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := NewChannel[int]()
|
||||
intStream := c.Generate(ctx, 1, 2, 3)
|
||||
|
||||
fmt.Println(<-intStream)
|
||||
fmt.Println(<-intStream)
|
||||
fmt.Println(<-intStream)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 3
|
||||
}
|
||||
|
||||
func ExampleChannel_Repeat() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := NewChannel[int]()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 4)
|
||||
|
||||
for v := range intStream {
|
||||
fmt.Println(v)
|
||||
}
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 1
|
||||
// 2
|
||||
}
|
||||
|
||||
func ExampleChannel_RepeatFn() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
fn := func() string {
|
||||
return "hello"
|
||||
}
|
||||
|
||||
c := NewChannel[string]()
|
||||
intStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3)
|
||||
|
||||
for v := range intStream {
|
||||
fmt.Println(v)
|
||||
}
|
||||
// Output:
|
||||
// hello
|
||||
// hello
|
||||
// hello
|
||||
}
|
||||
|
||||
func ExampleChannel_Take() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
numbers := make(chan int, 5)
|
||||
numbers <- 1
|
||||
numbers <- 2
|
||||
numbers <- 3
|
||||
numbers <- 4
|
||||
numbers <- 5
|
||||
defer close(numbers)
|
||||
|
||||
c := NewChannel[int]()
|
||||
intStream := c.Take(ctx, numbers, 3)
|
||||
|
||||
for v := range intStream {
|
||||
fmt.Println(v)
|
||||
}
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 3
|
||||
}
|
||||
|
||||
func ExampleChannel_FanIn() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := NewChannel[int]()
|
||||
channels := make([]<-chan int, 2)
|
||||
|
||||
for i := 0; i < 2; i++ {
|
||||
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 2)
|
||||
}
|
||||
|
||||
chs := c.FanIn(ctx, channels...)
|
||||
|
||||
for v := range chs {
|
||||
fmt.Println(v) //1 1 0 0 or 0 0 1 1
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func ExampleChannel_Or() {
|
||||
sig := func(after time.Duration) <-chan any {
|
||||
c := make(chan any)
|
||||
go func() {
|
||||
defer close(c)
|
||||
time.Sleep(after)
|
||||
}()
|
||||
return c
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
|
||||
c := NewChannel[any]()
|
||||
<-c.Or(
|
||||
sig(1*time.Second),
|
||||
sig(2*time.Second),
|
||||
sig(3*time.Second),
|
||||
)
|
||||
|
||||
if time.Since(start).Seconds() < 2 {
|
||||
fmt.Println("ok")
|
||||
}
|
||||
// Output:
|
||||
// ok
|
||||
}
|
||||
|
||||
func ExampleChannel_OrDone() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := NewChannel[int]()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1), 3)
|
||||
|
||||
for v := range c.OrDone(ctx, intStream) {
|
||||
fmt.Println(v)
|
||||
}
|
||||
// Output:
|
||||
// 1
|
||||
// 1
|
||||
// 1
|
||||
}
|
||||
|
||||
func ExampleChannel_Tee() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := NewChannel[int]()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1), 2)
|
||||
|
||||
ch1, ch2 := c.Tee(ctx, intStream)
|
||||
|
||||
for v := range ch1 {
|
||||
fmt.Println(v)
|
||||
fmt.Println(<-ch2)
|
||||
}
|
||||
// Output:
|
||||
// 1
|
||||
// 1
|
||||
// 1
|
||||
// 1
|
||||
}
|
||||
|
||||
func ExampleChannel_Bridge() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := NewChannel[int]()
|
||||
genVals := func() <-chan <-chan int {
|
||||
out := make(chan (<-chan int))
|
||||
go func() {
|
||||
defer close(out)
|
||||
for i := 1; i <= 5; i++ {
|
||||
stream := make(chan int, 1)
|
||||
stream <- i
|
||||
close(stream)
|
||||
out <- stream
|
||||
}
|
||||
}()
|
||||
return out
|
||||
}
|
||||
|
||||
for v := range c.Bridge(ctx, genVals()) {
|
||||
fmt.Println(v)
|
||||
}
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 3
|
||||
// 4
|
||||
// 5
|
||||
}
|
||||
@@ -14,12 +14,9 @@ func TestGenerate(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := NewChannel()
|
||||
c := NewChannel[int]()
|
||||
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)
|
||||
@@ -31,12 +28,9 @@ func TestRepeat(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := NewChannel()
|
||||
c := NewChannel[int]()
|
||||
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)
|
||||
@@ -50,17 +44,13 @@ func TestRepeatFn(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
fn := func() any {
|
||||
fn := func() string {
|
||||
s := "a"
|
||||
return s
|
||||
}
|
||||
c := NewChannel()
|
||||
c := NewChannel[string]()
|
||||
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)
|
||||
@@ -72,7 +62,7 @@ func TestTake(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
numbers := make(chan any, 5)
|
||||
numbers := make(chan int, 5)
|
||||
numbers <- 1
|
||||
numbers <- 2
|
||||
numbers <- 3
|
||||
@@ -80,7 +70,7 @@ func TestTake(t *testing.T) {
|
||||
numbers <- 5
|
||||
defer close(numbers)
|
||||
|
||||
c := NewChannel()
|
||||
c := NewChannel[int]()
|
||||
intStream := c.Take(ctx, numbers, 3)
|
||||
|
||||
assert.Equal(1, <-intStream)
|
||||
@@ -94,8 +84,8 @@ func TestFanIn(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := NewChannel()
|
||||
channels := make([]<-chan any, 3)
|
||||
c := NewChannel[int]()
|
||||
channels := make([]<-chan int, 3)
|
||||
|
||||
for i := 0; i < 3; i++ {
|
||||
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 3)
|
||||
@@ -124,7 +114,7 @@ func TestOr(t *testing.T) {
|
||||
|
||||
start := time.Now()
|
||||
|
||||
c := NewChannel()
|
||||
c := NewChannel[any]()
|
||||
<-c.Or(
|
||||
sig(1*time.Second),
|
||||
sig(2*time.Second),
|
||||
@@ -133,9 +123,7 @@ func TestOr(t *testing.T) {
|
||||
sig(5*time.Second),
|
||||
)
|
||||
|
||||
t.Logf("done after %v", time.Since(start))
|
||||
|
||||
assert.Equal(1, 1)
|
||||
assert.Equal(true, time.Since(start).Seconds() < 2)
|
||||
}
|
||||
|
||||
func TestOrDone(t *testing.T) {
|
||||
@@ -144,16 +132,12 @@ func TestOrDone(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := NewChannel()
|
||||
c := NewChannel[int]()
|
||||
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, val)
|
||||
}
|
||||
|
||||
assert.Equal(1, res)
|
||||
}
|
||||
|
||||
func TestTee(t *testing.T) {
|
||||
@@ -162,15 +146,13 @@ func TestTee(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := NewChannel()
|
||||
c := NewChannel[int]()
|
||||
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)
|
||||
}
|
||||
@@ -182,13 +164,13 @@ func TestBridge(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := NewChannel()
|
||||
genVals := func() <-chan <-chan any {
|
||||
chanStream := make(chan (<-chan any))
|
||||
c := NewChannel[int]()
|
||||
genVals := func() <-chan <-chan int {
|
||||
chanStream := make(chan (<-chan int))
|
||||
go func() {
|
||||
defer close(chanStream)
|
||||
for i := 0; i < 10; i++ {
|
||||
stream := make(chan any, 1)
|
||||
stream := make(chan int, 1)
|
||||
stream <- i
|
||||
close(stream)
|
||||
chanStream <- stream
|
||||
|
||||
@@ -13,6 +13,7 @@ import "reflect"
|
||||
// If the type has an IsZero() bool method, the opposite value is returned.
|
||||
// Slices and maps are truthy if they have a length greater than zero.
|
||||
// All other types are truthy if they are not their zero value.
|
||||
// Play: https://go.dev/play/p/ETzeDJRSvhm
|
||||
func Bool[T any](value T) bool {
|
||||
switch m := any(value).(type) {
|
||||
case interface{ Bool() bool }:
|
||||
@@ -34,40 +35,47 @@ func reflectValue(vp any) bool {
|
||||
}
|
||||
|
||||
// And returns true if both a and b are truthy.
|
||||
// Play: https://go.dev/play/p/W1SSUmt6pvr
|
||||
func And[T, U any](a T, b U) bool {
|
||||
return Bool(a) && Bool(b)
|
||||
}
|
||||
|
||||
// Or returns false iff neither a nor b is truthy.
|
||||
// Or returns false if neither a nor b is truthy.
|
||||
// Play: https://go.dev/play/p/UlQTxHaeEkq
|
||||
func Or[T, U any](a T, b U) bool {
|
||||
return Bool(a) || Bool(b)
|
||||
}
|
||||
|
||||
// Xor returns true iff a or b but not both is truthy.
|
||||
// Xor returns true if a or b but not both is truthy.
|
||||
// Play: https://go.dev/play/p/gObZrW7ZbG8
|
||||
func Xor[T, U any](a T, b U) bool {
|
||||
valA := Bool(a)
|
||||
valB := Bool(b)
|
||||
return (valA || valB) && valA != valB
|
||||
}
|
||||
|
||||
// Nor returns true iff neither a nor b is truthy.
|
||||
// Nor returns true if neither a nor b is truthy.
|
||||
// Play: https://go.dev/play/p/g2j08F_zZky
|
||||
func Nor[T, U any](a T, b U) bool {
|
||||
return !(Bool(a) || Bool(b))
|
||||
}
|
||||
|
||||
// Xnor returns true iff both a and b or neither a nor b are truthy.
|
||||
// Xnor returns true if both a and b or neither a nor b are truthy.
|
||||
// Play: https://go.dev/play/p/OuDB9g51643
|
||||
func Xnor[T, U any](a T, b U) bool {
|
||||
valA := Bool(a)
|
||||
valB := Bool(b)
|
||||
return (valA && valB) || (!valA && !valB)
|
||||
}
|
||||
|
||||
// Nand returns false iff both a and b are truthy.
|
||||
// Nand returns false if both a and b are truthy.
|
||||
// Play: https://go.dev/play/p/vSRMLxLIbq8
|
||||
func Nand[T, U any](a T, b U) bool {
|
||||
return !Bool(a) || !Bool(b)
|
||||
}
|
||||
|
||||
// TernaryOperator checks the value of param `isTrue`, if true return ifValue else return elseValue
|
||||
// TernaryOperator checks the value of param `isTrue`, if true return ifValue else return elseValue.
|
||||
// Play: https://go.dev/play/p/ElllPZY0guT
|
||||
func TernaryOperator[T, U any](isTrue T, ifValue U, elseValue U) U {
|
||||
if Bool(isTrue) {
|
||||
return ifValue
|
||||
|
||||
163
condition/condition_example_test.go
Normal file
163
condition/condition_example_test.go
Normal file
@@ -0,0 +1,163 @@
|
||||
package condition
|
||||
|
||||
import "fmt"
|
||||
|
||||
func ExampleBool() {
|
||||
// bool
|
||||
result1 := Bool(false)
|
||||
result2 := Bool(true)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// integer
|
||||
result3 := Bool(0)
|
||||
result4 := Bool(1)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// string
|
||||
result5 := Bool("")
|
||||
result6 := Bool(" ")
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
|
||||
// slice
|
||||
var nums = []int{}
|
||||
result7 := Bool(nums)
|
||||
nums = append(nums, 1, 2)
|
||||
result8 := Bool(nums)
|
||||
fmt.Println(result7)
|
||||
fmt.Println(result8)
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// true
|
||||
// false
|
||||
// true
|
||||
// false
|
||||
// true
|
||||
// false
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleAnd() {
|
||||
result1 := And(0, 1)
|
||||
result2 := And(0, "")
|
||||
result3 := And(0, "0")
|
||||
result4 := And(1, "0")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleOr() {
|
||||
result1 := Or(0, "")
|
||||
result2 := Or(0, 1)
|
||||
result3 := Or(0, "0")
|
||||
result4 := Or(1, "0")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleXor() {
|
||||
result1 := Xor(0, 0)
|
||||
result2 := Xor(1, 1)
|
||||
result3 := Xor(0, 1)
|
||||
result4 := Xor(1, 0)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// false
|
||||
// true
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleNor() {
|
||||
result1 := Nor(0, 0)
|
||||
result2 := Nor(1, 1)
|
||||
result3 := Nor(0, 1)
|
||||
result4 := Nor(1, 0)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleXnor() {
|
||||
result1 := Xnor(0, 0)
|
||||
result2 := Xnor(1, 1)
|
||||
result3 := Xnor(0, 1)
|
||||
result4 := Xnor(1, 0)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleNand() {
|
||||
result1 := Nand(0, 0)
|
||||
result2 := Nand(1, 0)
|
||||
result3 := Nand(0, 1)
|
||||
result4 := Nand(1, 1)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleTernaryOperator() {
|
||||
conditionTrue := 2 > 1
|
||||
result1 := TernaryOperator(conditionTrue, 0, 1)
|
||||
fmt.Println(result1)
|
||||
|
||||
conditionFalse := 2 > 3
|
||||
result2 := TernaryOperator(conditionFalse, 0, 1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
// 1
|
||||
}
|
||||
@@ -17,12 +17,14 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ToBool convert string to a boolean
|
||||
// ToBool convert string to boolean.
|
||||
// Play: https://go.dev/play/p/ARht2WnGdIN
|
||||
func ToBool(s string) (bool, error) {
|
||||
return strconv.ParseBool(s)
|
||||
}
|
||||
|
||||
// ToBytes convert interface to bytes
|
||||
// ToBytes convert value to byte slice.
|
||||
// Play: https://go.dev/play/p/fAMXYFDvOvr
|
||||
func ToBytes(value any) ([]byte, error) {
|
||||
v := reflect.ValueOf(value)
|
||||
|
||||
@@ -63,7 +65,8 @@ func ToBytes(value any) ([]byte, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// ToChar convert string to char slice
|
||||
// ToChar convert string to char slice.
|
||||
// Play: https://go.dev/play/p/JJ1SvbFkVdM
|
||||
func ToChar(s string) []string {
|
||||
c := make([]string, 0)
|
||||
if len(s) == 0 {
|
||||
@@ -75,7 +78,8 @@ func ToChar(s string) []string {
|
||||
return c
|
||||
}
|
||||
|
||||
// ToChannel convert a array of elements to a read-only channels
|
||||
// ToChannel convert a slice of elements to a read-only channel.
|
||||
// Play: https://go.dev/play/p/hOx_oYZbAnL
|
||||
func ToChannel[T any](array []T) <-chan T {
|
||||
ch := make(chan T)
|
||||
|
||||
@@ -91,53 +95,58 @@ func ToChannel[T any](array []T) <-chan T {
|
||||
|
||||
// ToString convert value to string
|
||||
// for number, string, []byte, will convert to string
|
||||
// for other type (slice, map, array, struct) will call json.Marshal
|
||||
// for other type (slice, map, array, struct) will call json.Marshal.
|
||||
// Play: https://go.dev/play/p/nF1zOOslpQq
|
||||
func ToString(value any) string {
|
||||
if value == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
switch value.(type) {
|
||||
switch val := value.(type) {
|
||||
case float32:
|
||||
return strconv.FormatFloat(float64(value.(float32)), 'f', -1, 32)
|
||||
return strconv.FormatFloat(float64(val), 'f', -1, 32)
|
||||
case float64:
|
||||
return strconv.FormatFloat(value.(float64), 'f', -1, 64)
|
||||
return strconv.FormatFloat(val, 'f', -1, 64)
|
||||
case int:
|
||||
return strconv.FormatInt(int64(value.(int)), 10)
|
||||
return strconv.FormatInt(int64(val), 10)
|
||||
case int8:
|
||||
return strconv.FormatInt(int64(value.(int8)), 10)
|
||||
return strconv.FormatInt(int64(val), 10)
|
||||
case int16:
|
||||
return strconv.FormatInt(int64(value.(int16)), 10)
|
||||
return strconv.FormatInt(int64(val), 10)
|
||||
case int32:
|
||||
return strconv.FormatInt(int64(value.(int32)), 10)
|
||||
return strconv.FormatInt(int64(val), 10)
|
||||
case int64:
|
||||
return strconv.FormatInt(value.(int64), 10)
|
||||
return strconv.FormatInt(val, 10)
|
||||
case uint:
|
||||
return strconv.FormatUint(uint64(value.(uint)), 10)
|
||||
return strconv.FormatUint(uint64(val), 10)
|
||||
case uint8:
|
||||
return strconv.FormatUint(uint64(value.(uint8)), 10)
|
||||
return strconv.FormatUint(uint64(val), 10)
|
||||
case uint16:
|
||||
return strconv.FormatUint(uint64(value.(uint16)), 10)
|
||||
return strconv.FormatUint(uint64(val), 10)
|
||||
case uint32:
|
||||
return strconv.FormatUint(uint64(value.(uint32)), 10)
|
||||
return strconv.FormatUint(uint64(val), 10)
|
||||
case uint64:
|
||||
return strconv.FormatUint(value.(uint64), 10)
|
||||
return strconv.FormatUint(val, 10)
|
||||
case string:
|
||||
return value.(string)
|
||||
return val
|
||||
case []byte:
|
||||
return string(value.([]byte))
|
||||
return string(val)
|
||||
default:
|
||||
newValue, _ := json.Marshal(value)
|
||||
return string(newValue)
|
||||
b, err := json.Marshal(val)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return string(b)
|
||||
|
||||
// todo: maybe we should't supprt other type convertion
|
||||
// todo: maybe we should't supprt other type conversion
|
||||
// v := reflect.ValueOf(value)
|
||||
// log.Panicf("Unsupported data type: %s ", v.String())
|
||||
// return ""
|
||||
}
|
||||
}
|
||||
|
||||
// ToJson convert value to a valid json string
|
||||
// ToJson convert value to a json string.
|
||||
// Play: https://go.dev/play/p/2rLIkMmXWvR
|
||||
func ToJson(value any) (string, error) {
|
||||
result, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
@@ -147,7 +156,8 @@ func ToJson(value any) (string, error) {
|
||||
return string(result), nil
|
||||
}
|
||||
|
||||
// ToFloat convert value to a float64, if input is not a float return 0.0 and error
|
||||
// ToFloat convert value to float64, if input is not a float return 0.0 and error.
|
||||
// Play: https://go.dev/play/p/4YTmPCibqHJ
|
||||
func ToFloat(value any) (float64, error) {
|
||||
v := reflect.ValueOf(value)
|
||||
|
||||
@@ -174,12 +184,13 @@ func ToFloat(value any) (float64, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// ToInt convert value to a int64, if input is not a numeric format return 0 and error
|
||||
// ToInt convert value to int64 value, if input is not numerical, return 0 and error.
|
||||
// Play: https://go.dev/play/p/9_h9vIt-QZ_b
|
||||
func ToInt(value any) (int64, error) {
|
||||
v := reflect.ValueOf(value)
|
||||
|
||||
var result int64
|
||||
err := fmt.Errorf("ToInt: invalid interface type %T", value)
|
||||
err := fmt.Errorf("ToInt: invalid value type %T", value)
|
||||
switch value.(type) {
|
||||
case int, int8, int16, int32, int64:
|
||||
result = v.Int()
|
||||
@@ -201,12 +212,14 @@ func ToInt(value any) (int64, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// ToPointer returns a pointer to this value
|
||||
// ToPointer returns a pointer to passed value.
|
||||
// Play: https://go.dev/play/p/ASf_etHNlw1
|
||||
func ToPointer[T any](value T) *T {
|
||||
return &value
|
||||
}
|
||||
|
||||
// ToMap convert a slice or an array of structs to a map based on iteratee function
|
||||
// ToMap convert a slice of structs to a map based on iteratee function.
|
||||
// Play: https://go.dev/play/p/tVFy7E-t24l
|
||||
func ToMap[T any, K comparable, V any](array []T, iteratee func(T) (K, V)) map[K]V {
|
||||
result := make(map[K]V, len(array))
|
||||
for _, item := range array {
|
||||
@@ -218,7 +231,8 @@ func ToMap[T any, K comparable, V any](array []T, iteratee func(T) (K, V)) map[K
|
||||
}
|
||||
|
||||
// StructToMap convert struct to map, only convert exported struct field
|
||||
// map key is specified same as struct field tag `json` value
|
||||
// map key is specified same as struct field tag `json` value.
|
||||
// Play: https://go.dev/play/p/KYGYJqNUBOI
|
||||
func StructToMap(value any) (map[string]any, error) {
|
||||
v := reflect.ValueOf(value)
|
||||
t := reflect.TypeOf(value)
|
||||
@@ -247,7 +261,8 @@ func StructToMap(value any) (map[string]any, error) {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// MapToSlice convert a map to a slice based on iteratee function
|
||||
// MapToSlice convert map to slice based on iteratee function.
|
||||
// Play: https://go.dev/play/p/dmX4Ix5V6Wl
|
||||
func MapToSlice[T any, K comparable, V any](aMap map[K]V, iteratee func(K, V) T) []T {
|
||||
result := make([]T, 0, len(aMap))
|
||||
|
||||
@@ -258,7 +273,8 @@ func MapToSlice[T any, K comparable, V any](aMap map[K]V, iteratee func(K, V) T)
|
||||
return result
|
||||
}
|
||||
|
||||
// ColorHexToRGB convert hex color to rgb color
|
||||
// ColorHexToRGB convert hex color to rgb color.
|
||||
// Play: https://go.dev/play/p/o7_ft-JCJBV
|
||||
func ColorHexToRGB(colorHex string) (red, green, blue int) {
|
||||
colorHex = strings.TrimPrefix(colorHex, "#")
|
||||
color64, err := strconv.ParseInt(colorHex, 16, 32)
|
||||
@@ -269,7 +285,8 @@ func ColorHexToRGB(colorHex string) (red, green, blue int) {
|
||||
return color >> 16, (color & 0x00FF00) >> 8, color & 0x0000FF
|
||||
}
|
||||
|
||||
// ColorRGBToHex convert rgb color to hex color
|
||||
// ColorRGBToHex convert rgb color to hex color.
|
||||
// Play: https://go.dev/play/p/nzKS2Ro87J1
|
||||
func ColorRGBToHex(red, green, blue int) string {
|
||||
r := strconv.FormatInt(int64(red), 16)
|
||||
g := strconv.FormatInt(int64(green), 16)
|
||||
@@ -288,7 +305,8 @@ func ColorRGBToHex(red, green, blue int) string {
|
||||
return "#" + r + g + b
|
||||
}
|
||||
|
||||
// EncodeByte encode data to byte
|
||||
// EncodeByte encode data to byte slice.
|
||||
// Play: https://go.dev/play/p/DVmM1G5JfuP
|
||||
func EncodeByte(data any) ([]byte, error) {
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
encoder := gob.NewEncoder(buffer)
|
||||
@@ -299,7 +317,8 @@ func EncodeByte(data any) ([]byte, error) {
|
||||
return buffer.Bytes(), nil
|
||||
}
|
||||
|
||||
// DecodeByte decode byte data to target object
|
||||
// DecodeByte decode byte slice data to target object.
|
||||
// Play: https://go.dev/play/p/zI6xsmuQRbn
|
||||
func DecodeByte(data []byte, target any) error {
|
||||
buffer := bytes.NewBuffer(data)
|
||||
decoder := gob.NewDecoder(buffer)
|
||||
|
||||
254
convertor/convertor_example_test.go
Normal file
254
convertor/convertor_example_test.go
Normal file
@@ -0,0 +1,254 @@
|
||||
package convertor
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func ExampleToBool() {
|
||||
cases := []string{"1", "true", "True", "false", "False", "0", "123", "0.0", "abc"}
|
||||
|
||||
for i := 0; i < len(cases); i++ {
|
||||
result, _ := ToBool(cases[i])
|
||||
fmt.Println(result)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleToBytes() {
|
||||
result1, _ := ToBytes(1)
|
||||
result2, _ := ToBytes("abc")
|
||||
result3, _ := ToBytes(true)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// [0 0 0 0 0 0 0 1]
|
||||
// [97 98 99]
|
||||
// [116 114 117 101]
|
||||
}
|
||||
|
||||
func ExampleToChar() {
|
||||
result1 := ToChar("")
|
||||
result2 := ToChar("abc")
|
||||
result3 := ToChar("1 2#3")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// []
|
||||
// [a b c]
|
||||
// [1 2 # 3]
|
||||
}
|
||||
|
||||
func ExampleToChannel() {
|
||||
ch := ToChannel([]int{1, 2, 3})
|
||||
result1 := <-ch
|
||||
result2 := <-ch
|
||||
result3 := <-ch
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 3
|
||||
}
|
||||
|
||||
func ExampleToString() {
|
||||
result1 := ToString("")
|
||||
result2 := ToString(nil)
|
||||
result3 := ToString(0)
|
||||
result4 := ToString(1.23)
|
||||
result5 := ToString(true)
|
||||
result6 := ToString(false)
|
||||
result7 := ToString([]int{1, 2, 3})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
fmt.Println(result7)
|
||||
|
||||
// Output:
|
||||
//
|
||||
//
|
||||
// 0
|
||||
// 1.23
|
||||
// true
|
||||
// false
|
||||
// [1,2,3]
|
||||
}
|
||||
|
||||
func ExampleToJson() {
|
||||
|
||||
aMap := map[string]int{"a": 1, "b": 2, "c": 3}
|
||||
result1, err := ToJson(aMap)
|
||||
if err != nil {
|
||||
fmt.Printf("%v", err)
|
||||
}
|
||||
fmt.Println(result1)
|
||||
|
||||
// Output:
|
||||
// {"a":1,"b":2,"c":3}
|
||||
}
|
||||
|
||||
func ExampleToFloat() {
|
||||
result1, _ := ToFloat("")
|
||||
result2, _ := ToFloat("abc")
|
||||
result3, _ := ToFloat("-1")
|
||||
result4, _ := ToFloat("-.11")
|
||||
result5, _ := ToFloat("1.23e3")
|
||||
result6, _ := ToFloat(true)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
// 0
|
||||
// -1
|
||||
// -0.11
|
||||
// 1230
|
||||
// 0
|
||||
}
|
||||
|
||||
func ExampleToInt() {
|
||||
result1, _ := ToInt("123")
|
||||
result2, _ := ToInt("-123")
|
||||
result3, _ := ToInt(float64(12.3))
|
||||
result4, _ := ToInt("abc")
|
||||
result5, _ := ToInt(true)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
|
||||
// Output:
|
||||
// 123
|
||||
// -123
|
||||
// 12
|
||||
// 0
|
||||
// 0
|
||||
}
|
||||
|
||||
func ExampleToPointer() {
|
||||
result := ToPointer(123)
|
||||
fmt.Println(*result)
|
||||
|
||||
// Output:
|
||||
// 123
|
||||
}
|
||||
|
||||
func ExampleToMap() {
|
||||
type Message struct {
|
||||
name string
|
||||
code int
|
||||
}
|
||||
messages := []Message{
|
||||
{name: "Hello", code: 100},
|
||||
{name: "Hi", code: 101},
|
||||
}
|
||||
result := ToMap(messages, func(msg Message) (int, string) {
|
||||
return msg.code, msg.name
|
||||
})
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// map[100:Hello 101:Hi]
|
||||
}
|
||||
|
||||
func ExampleStructToMap() {
|
||||
type People struct {
|
||||
Name string `json:"name"`
|
||||
age int
|
||||
}
|
||||
p := People{
|
||||
"test",
|
||||
100,
|
||||
}
|
||||
pm, _ := StructToMap(p)
|
||||
|
||||
fmt.Println(pm)
|
||||
|
||||
// Output:
|
||||
// map[name:test]
|
||||
}
|
||||
|
||||
func ExampleMapToSlice() {
|
||||
aMap := map[string]int{"a": 1, "b": 2, "c": 3}
|
||||
result := MapToSlice(aMap, func(key string, value int) string {
|
||||
return key + ":" + strconv.Itoa(value)
|
||||
})
|
||||
|
||||
fmt.Println(result) //[]string{"a:1", "c:3", "b:2"} (random order)
|
||||
}
|
||||
|
||||
func ExampleColorHexToRGB() {
|
||||
colorHex := "#003366"
|
||||
r, g, b := ColorHexToRGB(colorHex)
|
||||
|
||||
fmt.Println(r, g, b)
|
||||
|
||||
// Output:
|
||||
// 0 51 102
|
||||
}
|
||||
|
||||
func ExampleColorRGBToHex() {
|
||||
r := 0
|
||||
g := 51
|
||||
b := 102
|
||||
colorHex := ColorRGBToHex(r, g, b)
|
||||
|
||||
fmt.Println(colorHex)
|
||||
|
||||
// Output:
|
||||
// #003366
|
||||
}
|
||||
|
||||
func ExampleEncodeByte() {
|
||||
byteData, _ := EncodeByte("abc")
|
||||
fmt.Println(byteData)
|
||||
|
||||
// Output:
|
||||
// [6 12 0 3 97 98 99]
|
||||
}
|
||||
|
||||
func ExampleDecodeByte() {
|
||||
var obj string
|
||||
byteData := []byte{6, 12, 0, 3, 97, 98, 99}
|
||||
err := DecodeByte(byteData, &obj)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(obj)
|
||||
|
||||
// Output:
|
||||
// abc
|
||||
}
|
||||
@@ -27,14 +27,9 @@ func TestToChannel(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestToChannel")
|
||||
|
||||
ch := ToChannel([]int{1, 2, 3})
|
||||
val1, _ := <-ch
|
||||
assert.Equal(1, val1)
|
||||
|
||||
val2, _ := <-ch
|
||||
assert.Equal(2, val2)
|
||||
|
||||
val3, _ := <-ch
|
||||
assert.Equal(3, val3)
|
||||
assert.Equal(1, <-ch)
|
||||
assert.Equal(2, <-ch)
|
||||
assert.Equal(3, <-ch)
|
||||
|
||||
_, ok := <-ch
|
||||
assert.Equal(false, ok)
|
||||
@@ -254,6 +249,7 @@ func TestDecodeByte(t *testing.T) {
|
||||
|
||||
var obj string
|
||||
byteData := []byte{6, 12, 0, 3, 97, 98, 99}
|
||||
DecodeByte(byteData, &obj)
|
||||
err := DecodeByte(byteData, &obj)
|
||||
assert.IsNil(err)
|
||||
assert.Equal("abc", obj)
|
||||
}
|
||||
|
||||
@@ -17,15 +17,19 @@ import (
|
||||
// AesEcbEncrypt encrypt data with key use AES ECB algorithm
|
||||
// len(key) should be 16, 24 or 32
|
||||
func AesEcbEncrypt(data, key []byte) []byte {
|
||||
cipher, _ := aes.NewCipher(generateAesKey(key))
|
||||
length := (len(data) + aes.BlockSize) / aes.BlockSize
|
||||
plain := make([]byte, length*aes.BlockSize)
|
||||
|
||||
copy(plain, data)
|
||||
|
||||
pad := byte(len(plain) - len(data))
|
||||
for i := len(data); i < len(plain); i++ {
|
||||
plain[i] = pad
|
||||
}
|
||||
|
||||
encrypted := make([]byte, len(plain))
|
||||
cipher, _ := aes.NewCipher(generateAesKey(key))
|
||||
|
||||
for bs, be := 0, cipher.BlockSize(); bs <= len(data); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
|
||||
cipher.Encrypt(encrypted[bs:be], plain[bs:be])
|
||||
}
|
||||
@@ -108,27 +112,32 @@ func AesCfbEncrypt(data, key []byte) []byte {
|
||||
|
||||
encrypted := make([]byte, aes.BlockSize+len(data))
|
||||
iv := encrypted[:aes.BlockSize]
|
||||
|
||||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
stream := cipher.NewCFBEncrypter(block, iv)
|
||||
stream.XORKeyStream(encrypted[aes.BlockSize:], data)
|
||||
|
||||
return encrypted
|
||||
}
|
||||
|
||||
// AesCfbDecrypt decrypt data with key use AES CFB algorithm
|
||||
// len(encrypted) should be great than 16, len(key) should be 16, 24 or 32
|
||||
func AesCfbDecrypt(encrypted, key []byte) []byte {
|
||||
block, _ := aes.NewCipher(key)
|
||||
if len(encrypted) < aes.BlockSize {
|
||||
panic("encrypted data is too short")
|
||||
}
|
||||
|
||||
block, _ := aes.NewCipher(key)
|
||||
iv := encrypted[:aes.BlockSize]
|
||||
encrypted = encrypted[aes.BlockSize:]
|
||||
|
||||
stream := cipher.NewCFBDecrypter(block, iv)
|
||||
|
||||
stream.XORKeyStream(encrypted, encrypted)
|
||||
|
||||
return encrypted
|
||||
}
|
||||
|
||||
@@ -139,6 +148,7 @@ func AesOfbEncrypt(data, key []byte) []byte {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
data = pkcs7Padding(data, aes.BlockSize)
|
||||
encrypted := make([]byte, aes.BlockSize+len(data))
|
||||
iv := encrypted[:aes.BlockSize]
|
||||
@@ -148,6 +158,7 @@ func AesOfbEncrypt(data, key []byte) []byte {
|
||||
|
||||
stream := cipher.NewOFB(block, iv)
|
||||
stream.XORKeyStream(encrypted[aes.BlockSize:], data)
|
||||
|
||||
return encrypted
|
||||
}
|
||||
|
||||
@@ -170,5 +181,6 @@ func AesOfbDecrypt(data, key []byte) []byte {
|
||||
mode.XORKeyStream(decrypted, data)
|
||||
|
||||
decrypted = pkcs7UnPadding(decrypted)
|
||||
|
||||
return decrypted
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ import (
|
||||
// DesEcbEncrypt encrypt data with key use DES ECB algorithm
|
||||
// len(key) should be 8
|
||||
func DesEcbEncrypt(data, key []byte) []byte {
|
||||
cipher, _ := des.NewCipher(generateDesKey(key))
|
||||
length := (len(data) + des.BlockSize) / des.BlockSize
|
||||
plain := make([]byte, length*des.BlockSize)
|
||||
copy(plain, data)
|
||||
@@ -26,6 +25,8 @@ func DesEcbEncrypt(data, key []byte) []byte {
|
||||
}
|
||||
|
||||
encrypted := make([]byte, len(plain))
|
||||
cipher, _ := des.NewCipher(generateDesKey(key))
|
||||
|
||||
for bs, be := 0, cipher.BlockSize(); bs <= len(data); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
|
||||
cipher.Encrypt(encrypted[bs:be], plain[bs:be])
|
||||
}
|
||||
@@ -59,6 +60,7 @@ func DesCbcEncrypt(data, key []byte) []byte {
|
||||
|
||||
encrypted := make([]byte, des.BlockSize+len(data))
|
||||
iv := encrypted[:des.BlockSize]
|
||||
|
||||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@@ -33,7 +33,11 @@ func GenerateRsaKey(keySize int, priKeyFile, pubKeyFile string) error {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
pem.Encode(file, &block)
|
||||
err = pem.Encode(file, &block)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
file.Close()
|
||||
|
||||
// public key
|
||||
@@ -49,12 +53,16 @@ func GenerateRsaKey(keySize int, priKeyFile, pubKeyFile string) error {
|
||||
Bytes: derpText,
|
||||
}
|
||||
|
||||
//file,err = os.Create("rsa_public.pem")
|
||||
file, err = os.Create(pubKeyFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pem.Encode(file, &block)
|
||||
|
||||
err = pem.Encode(file, &block)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
file.Close()
|
||||
|
||||
return nil
|
||||
@@ -72,7 +80,11 @@ func RsaEncrypt(data []byte, pubKeyFileName string) []byte {
|
||||
}
|
||||
defer file.Close()
|
||||
buf := make([]byte, fileInfo.Size())
|
||||
file.Read(buf)
|
||||
|
||||
_, err = file.Read(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
block, _ := pem.Decode(buf)
|
||||
|
||||
@@ -101,7 +113,11 @@ func RsaDecrypt(data []byte, privateKeyFileName string) []byte {
|
||||
}
|
||||
buf := make([]byte, fileInfo.Size())
|
||||
defer file.Close()
|
||||
file.Read(buf)
|
||||
|
||||
_, err = file.Read(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
block, _ := pem.Decode(buf)
|
||||
|
||||
|
||||
@@ -146,9 +146,9 @@ func (h *MaxHeap[T]) PrintStructure() {
|
||||
lastNum := powerTwo(level - 1)
|
||||
lastLen := lastNum + (lastNum - 1)
|
||||
|
||||
heapTree := make([][]string, level, level)
|
||||
heapTree := make([][]string, level)
|
||||
for i := 0; i < level; i++ {
|
||||
heapTree[i] = make([]string, lastLen, lastLen)
|
||||
heapTree[i] = make([]string, lastLen)
|
||||
for j := 0; j < lastLen; j++ {
|
||||
heapTree[i][j] = ""
|
||||
}
|
||||
@@ -169,9 +169,9 @@ func (h *MaxHeap[T]) PrintStructure() {
|
||||
for n := 0; n < lastLen; n++ {
|
||||
val := heapTree[m][n]
|
||||
if val == "" {
|
||||
fmt.Printf(" ")
|
||||
fmt.Print(" ")
|
||||
} else {
|
||||
fmt.Printf(val)
|
||||
fmt.Print(val)
|
||||
}
|
||||
}
|
||||
fmt.Println()
|
||||
|
||||
@@ -30,8 +30,6 @@ func TestMaxHeap_BuildMaxHeap(t *testing.T) {
|
||||
assert.Equal(expected, heap.data)
|
||||
|
||||
assert.Equal(12, heap.Size())
|
||||
|
||||
heap.PrintStructure()
|
||||
}
|
||||
|
||||
func TestMaxHeap_Push(t *testing.T) {
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
package datastructure
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/duke-git/lancet/v2/datastructure"
|
||||
)
|
||||
|
||||
// DoublyLink is a linked list. Whose node has a generic Value, Pre pointer points to a previous node of the link, Next pointer points to a next node of the link.
|
||||
// DoublyLink is a linked list. Whose node has a generic Value, Pre pointer points to a previous node of the dl, Next pointer points to a next node of the dl.
|
||||
type DoublyLink[T any] struct {
|
||||
Head *datastructure.LinkNode[T]
|
||||
length int
|
||||
@@ -19,30 +18,30 @@ func NewDoublyLink[T any]() *DoublyLink[T] {
|
||||
}
|
||||
|
||||
// InsertAtHead insert value into doubly linklist at head index
|
||||
func (link *DoublyLink[T]) InsertAtHead(value T) {
|
||||
func (dl *DoublyLink[T]) InsertAtHead(value T) {
|
||||
newNode := datastructure.NewLinkNode(value)
|
||||
size := link.Size()
|
||||
size := dl.Size()
|
||||
|
||||
if size == 0 {
|
||||
link.Head = newNode
|
||||
link.length++
|
||||
dl.Head = newNode
|
||||
dl.length++
|
||||
return
|
||||
}
|
||||
|
||||
newNode.Next = link.Head
|
||||
newNode.Next = dl.Head
|
||||
newNode.Pre = nil
|
||||
|
||||
link.Head.Pre = newNode
|
||||
link.Head = newNode
|
||||
dl.Head.Pre = newNode
|
||||
dl.Head = newNode
|
||||
|
||||
link.length++
|
||||
dl.length++
|
||||
}
|
||||
|
||||
// InsertAtTail insert value into doubly linklist at tail index
|
||||
func (link *DoublyLink[T]) InsertAtTail(value T) {
|
||||
current := link.Head
|
||||
func (dl *DoublyLink[T]) InsertAtTail(value T) {
|
||||
current := dl.Head
|
||||
if current == nil {
|
||||
link.InsertAtHead(value)
|
||||
dl.InsertAtHead(value)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -55,28 +54,29 @@ func (link *DoublyLink[T]) InsertAtTail(value T) {
|
||||
newNode.Pre = current
|
||||
current.Next = newNode
|
||||
|
||||
link.length++
|
||||
dl.length++
|
||||
}
|
||||
|
||||
// InsertAt insert value into doubly linklist at index
|
||||
func (link *DoublyLink[T]) InsertAt(index int, value T) error {
|
||||
size := link.length
|
||||
// param `index` should between [0, length], if index do not meet the conditions, do nothing
|
||||
func (dl *DoublyLink[T]) InsertAt(index int, value T) {
|
||||
size := dl.length
|
||||
if index < 0 || index > size {
|
||||
return errors.New("param index should between 0 and the length of doubly link.")
|
||||
return
|
||||
}
|
||||
|
||||
if index == 0 {
|
||||
link.InsertAtHead(value)
|
||||
return nil
|
||||
dl.InsertAtHead(value)
|
||||
return
|
||||
}
|
||||
|
||||
if index == size {
|
||||
link.InsertAtTail(value)
|
||||
return nil
|
||||
dl.InsertAtTail(value)
|
||||
return
|
||||
}
|
||||
|
||||
i := 0
|
||||
current := link.Head
|
||||
current := dl.Head
|
||||
|
||||
for current != nil {
|
||||
if i == index-1 {
|
||||
@@ -85,38 +85,36 @@ func (link *DoublyLink[T]) InsertAt(index int, value T) error {
|
||||
newNode.Pre = current
|
||||
|
||||
current.Next = newNode
|
||||
link.length++
|
||||
dl.length++
|
||||
|
||||
return nil
|
||||
return
|
||||
}
|
||||
i++
|
||||
current = current.Next
|
||||
}
|
||||
|
||||
return errors.New("doubly link list no exist")
|
||||
}
|
||||
|
||||
// DeleteAtHead delete value in doubly linklist at head index
|
||||
func (link *DoublyLink[T]) DeleteAtHead() error {
|
||||
if link.Head == nil {
|
||||
return errors.New("doubly link list no exist")
|
||||
func (dl *DoublyLink[T]) DeleteAtHead() {
|
||||
if dl.Head == nil {
|
||||
return
|
||||
}
|
||||
current := link.Head
|
||||
link.Head = current.Next
|
||||
link.Head.Pre = nil
|
||||
link.length--
|
||||
|
||||
return nil
|
||||
current := dl.Head
|
||||
dl.Head = current.Next
|
||||
dl.Head.Pre = nil
|
||||
dl.length--
|
||||
}
|
||||
|
||||
// DeleteAtTail delete value in doubly linklist at tail index
|
||||
func (link *DoublyLink[T]) DeleteAtTail() error {
|
||||
if link.Head == nil {
|
||||
return errors.New("doubly link list no exist")
|
||||
// DeleteAtTail delete value in doubly linklist at tail
|
||||
func (dl *DoublyLink[T]) DeleteAtTail() {
|
||||
if dl.Head == nil {
|
||||
return
|
||||
}
|
||||
current := link.Head
|
||||
|
||||
current := dl.Head
|
||||
if current.Next == nil {
|
||||
return link.DeleteAtHead()
|
||||
dl.DeleteAtHead()
|
||||
}
|
||||
|
||||
for current.Next.Next != nil {
|
||||
@@ -124,45 +122,44 @@ func (link *DoublyLink[T]) DeleteAtTail() error {
|
||||
}
|
||||
|
||||
current.Next = nil
|
||||
link.length--
|
||||
return nil
|
||||
dl.length--
|
||||
}
|
||||
|
||||
// DeleteAt delete value in doubly linklist at index
|
||||
func (link *DoublyLink[T]) DeleteAt(index int) error {
|
||||
if link.Head == nil {
|
||||
return errors.New("doubly link list no exist")
|
||||
// param `index` should be [0, len(DoublyLink)-1]
|
||||
func (dl *DoublyLink[T]) DeleteAt(index int) {
|
||||
if dl.Head == nil {
|
||||
return
|
||||
}
|
||||
current := link.Head
|
||||
|
||||
current := dl.Head
|
||||
if current.Next == nil || index == 0 {
|
||||
return link.DeleteAtHead()
|
||||
dl.DeleteAtHead()
|
||||
}
|
||||
|
||||
if index == link.length-1 {
|
||||
return link.DeleteAtTail()
|
||||
if index == dl.length-1 {
|
||||
dl.DeleteAtTail()
|
||||
}
|
||||
|
||||
if index < 0 || index > link.length-1 {
|
||||
return errors.New("param index should between 0 and link size -1.")
|
||||
if index < 0 || index > dl.length-1 {
|
||||
return
|
||||
}
|
||||
|
||||
i := 0
|
||||
for current != nil {
|
||||
if i == index-1 {
|
||||
current.Next = current.Next.Next
|
||||
link.length--
|
||||
return nil
|
||||
dl.length--
|
||||
return
|
||||
}
|
||||
i++
|
||||
current = current.Next
|
||||
}
|
||||
|
||||
return errors.New("delete error")
|
||||
}
|
||||
|
||||
// Reverse the linked list
|
||||
func (link *DoublyLink[T]) Reverse() {
|
||||
current := link.Head
|
||||
func (dl *DoublyLink[T]) Reverse() {
|
||||
current := dl.Head
|
||||
var temp *datastructure.LinkNode[T]
|
||||
|
||||
for current != nil {
|
||||
@@ -173,20 +170,20 @@ func (link *DoublyLink[T]) Reverse() {
|
||||
}
|
||||
|
||||
if temp != nil {
|
||||
link.Head = temp.Pre
|
||||
dl.Head = temp.Pre
|
||||
}
|
||||
}
|
||||
|
||||
// GetMiddleNode return node at middle index of linked list
|
||||
func (link *DoublyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] {
|
||||
if link.Head == nil {
|
||||
func (dl *DoublyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] {
|
||||
if dl.Head == nil {
|
||||
return nil
|
||||
}
|
||||
if link.Head.Next == nil {
|
||||
return link.Head
|
||||
if dl.Head.Next == nil {
|
||||
return dl.Head
|
||||
}
|
||||
fast := link.Head
|
||||
slow := link.Head
|
||||
fast := dl.Head
|
||||
slow := dl.Head
|
||||
|
||||
for fast != nil {
|
||||
fast = fast.Next
|
||||
@@ -202,14 +199,14 @@ func (link *DoublyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] {
|
||||
}
|
||||
|
||||
// Size return the count of doubly linked list
|
||||
func (link *DoublyLink[T]) Size() int {
|
||||
return link.length
|
||||
func (dl *DoublyLink[T]) Size() int {
|
||||
return dl.length
|
||||
}
|
||||
|
||||
// Values return slice of all doubly linklist node value
|
||||
func (link *DoublyLink[T]) Values() []T {
|
||||
func (dl *DoublyLink[T]) Values() []T {
|
||||
result := []T{}
|
||||
current := link.Head
|
||||
current := dl.Head
|
||||
for current != nil {
|
||||
result = append(result, current.Value)
|
||||
current = current.Next
|
||||
@@ -218,8 +215,8 @@ func (link *DoublyLink[T]) Values() []T {
|
||||
}
|
||||
|
||||
// Print all nodes info of a linked list
|
||||
func (link *DoublyLink[T]) Print() {
|
||||
current := link.Head
|
||||
func (dl *DoublyLink[T]) Print() {
|
||||
current := dl.Head
|
||||
info := "[ "
|
||||
for current != nil {
|
||||
info += fmt.Sprintf("%+v, ", current)
|
||||
@@ -229,13 +226,13 @@ func (link *DoublyLink[T]) Print() {
|
||||
fmt.Println(info)
|
||||
}
|
||||
|
||||
// IsEmpty checks if link is empty or not
|
||||
func (link *DoublyLink[T]) IsEmpty() bool {
|
||||
return link.length == 0
|
||||
// IsEmpty checks if dl is empty or not
|
||||
func (dl *DoublyLink[T]) IsEmpty() bool {
|
||||
return dl.length == 0
|
||||
}
|
||||
|
||||
// Clear all nodes in doubly linklist
|
||||
func (link *DoublyLink[T]) Clear() {
|
||||
link.Head = nil
|
||||
link.length = 0
|
||||
func (dl *DoublyLink[T]) Clear() {
|
||||
dl.Head = nil
|
||||
dl.length = 0
|
||||
}
|
||||
|
||||
@@ -41,29 +41,24 @@ func TestDoublyLink_InsertAt(t *testing.T) {
|
||||
|
||||
link := NewDoublyLink[int]()
|
||||
|
||||
err := link.InsertAt(1, 1)
|
||||
assert.IsNotNil(err)
|
||||
link.InsertAt(1, 1) //do nothing
|
||||
|
||||
link.InsertAt(0, 1)
|
||||
link.InsertAt(1, 2)
|
||||
link.InsertAt(2, 4)
|
||||
link.InsertAt(2, 3)
|
||||
|
||||
link.Print()
|
||||
|
||||
expected := []int{1, 2, 3, 4}
|
||||
values := link.Values()
|
||||
|
||||
assert.Equal(expected, values)
|
||||
|
||||
}
|
||||
|
||||
func TestDoublyLink_DeleteAtHead(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestDoublyLink_DeleteAtHead")
|
||||
|
||||
link := NewDoublyLink[int]()
|
||||
err := link.DeleteAtHead()
|
||||
assert.IsNotNil(err)
|
||||
link.DeleteAtHead()
|
||||
|
||||
link.InsertAtTail(1)
|
||||
link.InsertAtTail(2)
|
||||
@@ -71,7 +66,6 @@ func TestDoublyLink_DeleteAtHead(t *testing.T) {
|
||||
link.InsertAtTail(4)
|
||||
|
||||
link.DeleteAtHead()
|
||||
link.Print()
|
||||
|
||||
expected := []int{2, 3, 4}
|
||||
values := link.Values()
|
||||
@@ -83,8 +77,7 @@ func TestDoublyLink_DeleteAtTail(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestDoublyLink_DeleteAtTail")
|
||||
|
||||
link := NewDoublyLink[int]()
|
||||
err := link.DeleteAtTail()
|
||||
assert.IsNotNil(err)
|
||||
link.DeleteAtTail()
|
||||
|
||||
link.InsertAtTail(1)
|
||||
link.InsertAtTail(2)
|
||||
@@ -92,7 +85,6 @@ func TestDoublyLink_DeleteAtTail(t *testing.T) {
|
||||
link.InsertAtTail(4)
|
||||
|
||||
link.DeleteAtTail()
|
||||
link.Print()
|
||||
|
||||
expected := []int{1, 2, 3}
|
||||
values := link.Values()
|
||||
@@ -104,8 +96,7 @@ func TestDoublyLink_DeleteAt(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestDoublyLink_DeleteAt")
|
||||
|
||||
link := NewDoublyLink[int]()
|
||||
err := link.DeleteAt(0)
|
||||
assert.IsNotNil(err)
|
||||
link.DeleteAt(0)
|
||||
|
||||
link.InsertAtTail(1)
|
||||
link.InsertAtTail(2)
|
||||
@@ -113,11 +104,7 @@ func TestDoublyLink_DeleteAt(t *testing.T) {
|
||||
link.InsertAtTail(4)
|
||||
link.InsertAtTail(5)
|
||||
|
||||
err = link.DeleteAt(5)
|
||||
assert.IsNotNil(err)
|
||||
|
||||
err = link.DeleteAt(0)
|
||||
assert.IsNil(err)
|
||||
link.DeleteAt(0)
|
||||
assert.Equal([]int{2, 3, 4, 5}, link.Values())
|
||||
|
||||
link.DeleteAt(3)
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
package datastructure
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/duke-git/lancet/v2/datastructure"
|
||||
)
|
||||
|
||||
// SinglyLink is a linked list. Whose node has a Value generics and Next pointer points to a next node of the link.
|
||||
// SinglyLink is a linked list. Whose node has a Value generics and Next pointer points to a next node of the sl.
|
||||
type SinglyLink[T any] struct {
|
||||
Head *datastructure.LinkNode[T]
|
||||
length int
|
||||
@@ -20,18 +19,18 @@ func NewSinglyLink[T any]() *SinglyLink[T] {
|
||||
}
|
||||
|
||||
// InsertAtHead insert value into singly linklist at head index
|
||||
func (link *SinglyLink[T]) InsertAtHead(value T) {
|
||||
func (sl *SinglyLink[T]) InsertAtHead(value T) {
|
||||
newNode := datastructure.NewLinkNode(value)
|
||||
newNode.Next = link.Head
|
||||
link.Head = newNode
|
||||
link.length++
|
||||
newNode.Next = sl.Head
|
||||
sl.Head = newNode
|
||||
sl.length++
|
||||
}
|
||||
|
||||
// InsertAtTail insert value into singly linklist at tail index
|
||||
func (link *SinglyLink[T]) InsertAtTail(value T) {
|
||||
current := link.Head
|
||||
func (sl *SinglyLink[T]) InsertAtTail(value T) {
|
||||
current := sl.Head
|
||||
if current == nil {
|
||||
link.InsertAtHead(value)
|
||||
sl.InsertAtHead(value)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -43,65 +42,63 @@ func (link *SinglyLink[T]) InsertAtTail(value T) {
|
||||
newNode.Next = nil
|
||||
current.Next = newNode
|
||||
|
||||
link.length++
|
||||
sl.length++
|
||||
}
|
||||
|
||||
// InsertAt insert value into singly linklist at index
|
||||
func (link *SinglyLink[T]) InsertAt(index int, value T) error {
|
||||
size := link.length
|
||||
// param `index` should between [0, len(SinglyLink)], if index do not meet the conditions, do nothing
|
||||
func (sl *SinglyLink[T]) InsertAt(index int, value T) {
|
||||
size := sl.length
|
||||
if index < 0 || index > size {
|
||||
return errors.New("param index should between 0 and the length of singly link.")
|
||||
return
|
||||
}
|
||||
|
||||
if index == 0 {
|
||||
link.InsertAtHead(value)
|
||||
return nil
|
||||
sl.InsertAtHead(value)
|
||||
return
|
||||
}
|
||||
|
||||
if index == size {
|
||||
link.InsertAtTail(value)
|
||||
return nil
|
||||
sl.InsertAtTail(value)
|
||||
return
|
||||
}
|
||||
|
||||
i := 0
|
||||
current := link.Head
|
||||
current := sl.Head
|
||||
|
||||
for current != nil {
|
||||
if i == index-1 {
|
||||
newNode := datastructure.NewLinkNode(value)
|
||||
newNode.Next = current.Next
|
||||
current.Next = newNode
|
||||
link.length++
|
||||
|
||||
return nil
|
||||
sl.length++
|
||||
return
|
||||
}
|
||||
i++
|
||||
current = current.Next
|
||||
}
|
||||
|
||||
return errors.New("singly link list no exist")
|
||||
}
|
||||
|
||||
// DeleteAtHead delete value in singly linklist at head index
|
||||
func (link *SinglyLink[T]) DeleteAtHead() error {
|
||||
if link.Head == nil {
|
||||
return errors.New("singly link list no exist")
|
||||
func (sl *SinglyLink[T]) DeleteAtHead() {
|
||||
if sl.Head == nil {
|
||||
return
|
||||
}
|
||||
current := link.Head
|
||||
link.Head = current.Next
|
||||
link.length--
|
||||
|
||||
return nil
|
||||
current := sl.Head
|
||||
sl.Head = current.Next
|
||||
sl.length--
|
||||
}
|
||||
|
||||
// DeleteAtTail delete value in singly linklist at tail index
|
||||
func (link *SinglyLink[T]) DeleteAtTail() error {
|
||||
if link.Head == nil {
|
||||
return errors.New("singly link list no exist")
|
||||
// DeleteAtTail delete value in singly linklist at tail
|
||||
func (sl *SinglyLink[T]) DeleteAtTail() {
|
||||
if sl.Head == nil {
|
||||
return
|
||||
}
|
||||
current := link.Head
|
||||
|
||||
current := sl.Head
|
||||
if current.Next == nil {
|
||||
return link.DeleteAtHead()
|
||||
sl.DeleteAtHead()
|
||||
}
|
||||
|
||||
for current.Next.Next != nil {
|
||||
@@ -109,68 +106,66 @@ func (link *SinglyLink[T]) DeleteAtTail() error {
|
||||
}
|
||||
|
||||
current.Next = nil
|
||||
link.length--
|
||||
return nil
|
||||
sl.length--
|
||||
}
|
||||
|
||||
// DeleteAt delete value in singly linklist at index
|
||||
func (link *SinglyLink[T]) DeleteAt(index int) error {
|
||||
if link.Head == nil {
|
||||
return errors.New("singly link list no exist")
|
||||
// param `index` should be [0, len(SinglyLink)-1]
|
||||
func (sl *SinglyLink[T]) DeleteAt(index int) {
|
||||
if sl.Head == nil {
|
||||
return
|
||||
}
|
||||
current := link.Head
|
||||
current := sl.Head
|
||||
if current.Next == nil || index == 0 {
|
||||
return link.DeleteAtHead()
|
||||
sl.DeleteAtHead()
|
||||
}
|
||||
|
||||
if index == link.length-1 {
|
||||
return link.DeleteAtTail()
|
||||
if index == sl.length-1 {
|
||||
sl.DeleteAtTail()
|
||||
}
|
||||
|
||||
if index < 0 || index > link.length-1 {
|
||||
return errors.New("param index should between 0 and link size -1.")
|
||||
if index < 0 || index > sl.length-1 {
|
||||
return
|
||||
}
|
||||
|
||||
i := 0
|
||||
for current != nil {
|
||||
if i == index-1 {
|
||||
current.Next = current.Next.Next
|
||||
link.length--
|
||||
return nil
|
||||
sl.length--
|
||||
return
|
||||
}
|
||||
i++
|
||||
current = current.Next
|
||||
}
|
||||
|
||||
return errors.New("delete error")
|
||||
}
|
||||
|
||||
// DeleteValue delete value in singly linklist
|
||||
func (link *SinglyLink[T]) DeleteValue(value T) {
|
||||
if link.Head == nil {
|
||||
func (sl *SinglyLink[T]) DeleteValue(value T) {
|
||||
if sl.Head == nil {
|
||||
return
|
||||
}
|
||||
dummyHead := datastructure.NewLinkNode(value)
|
||||
dummyHead.Next = link.Head
|
||||
dummyHead.Next = sl.Head
|
||||
current := dummyHead
|
||||
|
||||
for current.Next != nil {
|
||||
if reflect.DeepEqual(current.Next.Value, value) {
|
||||
current.Next = current.Next.Next
|
||||
link.length--
|
||||
sl.length--
|
||||
} else {
|
||||
current = current.Next
|
||||
}
|
||||
}
|
||||
|
||||
link.Head = dummyHead.Next
|
||||
sl.Head = dummyHead.Next
|
||||
}
|
||||
|
||||
// Reverse the linked list
|
||||
func (link *SinglyLink[T]) Reverse() {
|
||||
func (sl *SinglyLink[T]) Reverse() {
|
||||
var pre, next *datastructure.LinkNode[T]
|
||||
|
||||
current := link.Head
|
||||
current := sl.Head
|
||||
|
||||
for current != nil {
|
||||
next = current.Next
|
||||
@@ -179,19 +174,19 @@ func (link *SinglyLink[T]) Reverse() {
|
||||
current = next
|
||||
}
|
||||
|
||||
link.Head = pre
|
||||
sl.Head = pre
|
||||
}
|
||||
|
||||
// GetMiddleNode return node at middle index of linked list
|
||||
func (link *SinglyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] {
|
||||
if link.Head == nil {
|
||||
func (sl *SinglyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] {
|
||||
if sl.Head == nil {
|
||||
return nil
|
||||
}
|
||||
if link.Head.Next == nil {
|
||||
return link.Head
|
||||
if sl.Head.Next == nil {
|
||||
return sl.Head
|
||||
}
|
||||
fast := link.Head
|
||||
slow := link.Head
|
||||
fast := sl.Head
|
||||
slow := sl.Head
|
||||
|
||||
for fast != nil {
|
||||
fast = fast.Next
|
||||
@@ -207,14 +202,14 @@ func (link *SinglyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] {
|
||||
}
|
||||
|
||||
// Size return the count of singly linked list
|
||||
func (link *SinglyLink[T]) Size() int {
|
||||
return link.length
|
||||
func (sl *SinglyLink[T]) Size() int {
|
||||
return sl.length
|
||||
}
|
||||
|
||||
// Values return slice of all singly linklist node value
|
||||
func (link *SinglyLink[T]) Values() []T {
|
||||
func (sl *SinglyLink[T]) Values() []T {
|
||||
result := []T{}
|
||||
current := link.Head
|
||||
current := sl.Head
|
||||
for current != nil {
|
||||
result = append(result, current.Value)
|
||||
current = current.Next
|
||||
@@ -222,20 +217,20 @@ func (link *SinglyLink[T]) Values() []T {
|
||||
return result
|
||||
}
|
||||
|
||||
// IsEmpty checks if link is empty or not
|
||||
func (link *SinglyLink[T]) IsEmpty() bool {
|
||||
return link.length == 0
|
||||
// IsEmpty checks if sl is empty or not
|
||||
func (sl *SinglyLink[T]) IsEmpty() bool {
|
||||
return sl.length == 0
|
||||
}
|
||||
|
||||
// Clear all the node in singly linklist
|
||||
func (link *SinglyLink[T]) Clear() {
|
||||
link.Head = nil
|
||||
link.length = 0
|
||||
func (sl *SinglyLink[T]) Clear() {
|
||||
sl.Head = nil
|
||||
sl.length = 0
|
||||
}
|
||||
|
||||
// Print all nodes info of a linked list
|
||||
func (link *SinglyLink[T]) Print() {
|
||||
current := link.Head
|
||||
func (sl *SinglyLink[T]) Print() {
|
||||
current := sl.Head
|
||||
info := "[ "
|
||||
for current != nil {
|
||||
info += fmt.Sprintf("%+v, ", current)
|
||||
|
||||
@@ -41,25 +41,12 @@ func TestSinglyLink_InsertAt(t *testing.T) {
|
||||
|
||||
link := NewSinglyLink[int]()
|
||||
|
||||
err := link.InsertAt(1, 1)
|
||||
assert.IsNotNil(err)
|
||||
link.InsertAt(1, 1) //do nothing
|
||||
|
||||
err = link.InsertAt(0, 1)
|
||||
if err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
err = link.InsertAt(1, 2)
|
||||
if err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
err = link.InsertAt(2, 4)
|
||||
if err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
err = link.InsertAt(2, 3)
|
||||
if err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
link.InsertAt(0, 1)
|
||||
link.InsertAt(1, 2)
|
||||
link.InsertAt(2, 4)
|
||||
link.InsertAt(2, 3)
|
||||
|
||||
link.Print()
|
||||
|
||||
@@ -73,8 +60,8 @@ func TestSinglyLink_DeleteAtHead(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSinglyLink_DeleteAtHead")
|
||||
|
||||
link := NewSinglyLink[int]()
|
||||
err := link.DeleteAtHead()
|
||||
assert.IsNotNil(err)
|
||||
|
||||
link.DeleteAtHead()
|
||||
|
||||
link.InsertAtTail(1)
|
||||
link.InsertAtTail(2)
|
||||
@@ -94,8 +81,6 @@ func TestSinglyLink_DeleteAtTail(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSinglyLink_DeleteAtTail")
|
||||
|
||||
link := NewSinglyLink[int]()
|
||||
err := link.DeleteAtTail()
|
||||
assert.IsNotNil(err)
|
||||
|
||||
link.InsertAtTail(1)
|
||||
link.InsertAtTail(2)
|
||||
@@ -103,7 +88,6 @@ func TestSinglyLink_DeleteAtTail(t *testing.T) {
|
||||
link.InsertAtTail(4)
|
||||
|
||||
link.DeleteAtTail()
|
||||
link.Print()
|
||||
|
||||
expected := []int{1, 2, 3}
|
||||
values := link.Values()
|
||||
@@ -133,8 +117,6 @@ func TestSinglyLink_DeleteAt(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSinglyLink_DeleteAt")
|
||||
|
||||
link := NewSinglyLink[int]()
|
||||
err := link.DeleteAt(0)
|
||||
assert.IsNotNil(err)
|
||||
|
||||
link.InsertAtTail(1)
|
||||
link.InsertAtTail(2)
|
||||
@@ -142,11 +124,7 @@ func TestSinglyLink_DeleteAt(t *testing.T) {
|
||||
link.InsertAtTail(4)
|
||||
link.InsertAtTail(5)
|
||||
|
||||
err = link.DeleteAt(5)
|
||||
assert.IsNotNil(err)
|
||||
|
||||
err = link.DeleteAt(0)
|
||||
assert.IsNil(err)
|
||||
link.DeleteAt(0)
|
||||
assert.Equal([]int{2, 3, 4, 5}, link.Values())
|
||||
|
||||
link.DeleteAt(3)
|
||||
@@ -167,7 +145,6 @@ func TestSinglyLink_Reverse(t *testing.T) {
|
||||
link.InsertAtTail(4)
|
||||
|
||||
link.Reverse()
|
||||
link.Print()
|
||||
assert.Equal([]int{4, 3, 2, 1}, link.Values())
|
||||
}
|
||||
|
||||
|
||||
@@ -156,7 +156,7 @@ func (l *List[T]) DeleteAt(index int) {
|
||||
return
|
||||
}
|
||||
if index == size-1 {
|
||||
data = append(data[:index])
|
||||
data = data[:index]
|
||||
} else {
|
||||
data = append(data[:index], data[index+1:]...)
|
||||
}
|
||||
@@ -174,7 +174,7 @@ func (l *List[T]) DeleteIf(f func(T) bool) int {
|
||||
continue
|
||||
}
|
||||
if index == size-1 {
|
||||
data = append(data[:index])
|
||||
data = data[:index]
|
||||
} else {
|
||||
data = append(data[:index], data[index+1:]...)
|
||||
index--
|
||||
@@ -221,7 +221,7 @@ func (l *List[T]) IsEmpty() bool {
|
||||
|
||||
// Clear the data of list
|
||||
func (l *List[T]) Clear() {
|
||||
l.data = make([]T, 0, 0)
|
||||
l.data = make([]T, 0)
|
||||
}
|
||||
|
||||
// Clone return a copy of list
|
||||
@@ -235,7 +235,7 @@ func (l *List[T]) Clone() *List[T] {
|
||||
// Merge two list, return new list, don't change original list
|
||||
func (l *List[T]) Merge(other *List[T]) *List[T] {
|
||||
l1, l2 := len(l.data), len(other.data)
|
||||
ml := NewList(make([]T, l1+l2, l1+l2))
|
||||
ml := NewList(make([]T, l1+l2))
|
||||
|
||||
data := append([]T{}, append(l.data, other.data...)...)
|
||||
ml.data = data
|
||||
@@ -274,7 +274,7 @@ func (l *List[T]) Unique() {
|
||||
data := l.data
|
||||
size := len(data)
|
||||
|
||||
uniqueData := make([]T, 0, 0)
|
||||
uniqueData := make([]T, 0)
|
||||
for i := 0; i < size; i++ {
|
||||
value := data[i]
|
||||
skip := true
|
||||
@@ -305,7 +305,7 @@ func (l *List[T]) Union(other *List[T]) *List[T] {
|
||||
|
||||
// Intersection creates a new list whose element both be contained in list l and other
|
||||
func (l *List[T]) Intersection(other *List[T]) *List[T] {
|
||||
result := NewList(make([]T, 0, 0))
|
||||
result := NewList(make([]T, 0))
|
||||
|
||||
for _, v := range l.data {
|
||||
if other.Contain(v) {
|
||||
|
||||
@@ -18,8 +18,6 @@ func TestArrayQueue_Enqueue(t *testing.T) {
|
||||
data := queue.Data()
|
||||
size := queue.Size()
|
||||
|
||||
queue.Print()
|
||||
|
||||
assert.Equal(expected, data)
|
||||
assert.Equal(3, size)
|
||||
}
|
||||
@@ -35,7 +33,6 @@ func TestArrayQueue_Dequeue(t *testing.T) {
|
||||
val, ok := queue.Dequeue()
|
||||
assert.Equal(true, ok)
|
||||
|
||||
queue.Print()
|
||||
assert.Equal(1, val)
|
||||
assert.Equal([]int{2, 3}, queue.Data())
|
||||
}
|
||||
@@ -50,8 +47,6 @@ func TestArrayQueue_Front(t *testing.T) {
|
||||
|
||||
val := queue.Front()
|
||||
|
||||
queue.Print()
|
||||
|
||||
assert.Equal(1, val)
|
||||
assert.Equal([]int{1, 2, 3}, queue.Data())
|
||||
}
|
||||
@@ -66,8 +61,6 @@ func TestArrayQueue_Back(t *testing.T) {
|
||||
|
||||
val := queue.Back()
|
||||
|
||||
queue.Print()
|
||||
|
||||
assert.Equal(3, val)
|
||||
assert.Equal([]int{1, 2, 3}, queue.Data())
|
||||
}
|
||||
|
||||
@@ -10,31 +10,43 @@ 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.Print()
|
||||
err := queue.Enqueue(1)
|
||||
assert.IsNil(err)
|
||||
|
||||
err = queue.Enqueue(2)
|
||||
assert.IsNil(err)
|
||||
|
||||
err = queue.Enqueue(3)
|
||||
assert.IsNil(err)
|
||||
|
||||
err = queue.Enqueue(4)
|
||||
assert.IsNil(err)
|
||||
|
||||
err = queue.Enqueue(5)
|
||||
assert.IsNil(err)
|
||||
|
||||
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) {
|
||||
assert := internal.NewAssert(t, "TestCircularQueue_DeQueue")
|
||||
|
||||
queue := NewCircularQueue[int](6)
|
||||
queue := NewCircularQueue[int](4)
|
||||
assert.Equal(true, queue.IsEmpty())
|
||||
|
||||
queue.Enqueue(1)
|
||||
queue.Enqueue(2)
|
||||
queue.Enqueue(3)
|
||||
queue.Enqueue(4)
|
||||
queue.Enqueue(5)
|
||||
err := queue.Enqueue(1)
|
||||
assert.IsNil(err)
|
||||
|
||||
err = queue.Enqueue(2)
|
||||
assert.IsNil(err)
|
||||
|
||||
err = queue.Enqueue(3)
|
||||
assert.IsNil(err)
|
||||
|
||||
val, err := queue.Dequeue()
|
||||
assert.IsNil(err)
|
||||
@@ -43,11 +55,7 @@ func TestCircularQueue_Dequeue(t *testing.T) {
|
||||
assert.Equal(false, queue.IsFull())
|
||||
|
||||
val, _ = queue.Dequeue()
|
||||
queue.Print()
|
||||
assert.Equal(2, *val)
|
||||
|
||||
queue.Enqueue(6)
|
||||
queue.Print()
|
||||
assert.Equal(false, queue.IsFull())
|
||||
}
|
||||
|
||||
@@ -55,55 +63,52 @@ 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.Print()
|
||||
err := queue.Enqueue(1)
|
||||
assert.IsNil(err)
|
||||
|
||||
queue.Dequeue()
|
||||
queue.Dequeue()
|
||||
queue.Enqueue(6)
|
||||
queue.Enqueue(7)
|
||||
err = queue.Enqueue(2)
|
||||
assert.IsNil(err)
|
||||
|
||||
queue.Print()
|
||||
err = queue.Enqueue(3)
|
||||
assert.IsNil(err)
|
||||
|
||||
val := queue.Front()
|
||||
assert.Equal(3, val)
|
||||
assert.Equal(5, queue.Size())
|
||||
assert.IsNil(err)
|
||||
assert.Equal(1, val)
|
||||
assert.Equal(3, queue.Size())
|
||||
}
|
||||
|
||||
func TestCircularQueue_Back(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestCircularQueue_Back")
|
||||
|
||||
queue := NewCircularQueue[int](6)
|
||||
queue := NewCircularQueue[int](3)
|
||||
assert.Equal(true, queue.IsEmpty())
|
||||
|
||||
queue.Enqueue(1)
|
||||
queue.Enqueue(2)
|
||||
queue.Enqueue(3)
|
||||
queue.Enqueue(4)
|
||||
queue.Enqueue(5)
|
||||
err := queue.Enqueue(1)
|
||||
assert.IsNil(err)
|
||||
|
||||
queue.Print()
|
||||
assert.Equal(5, queue.Back())
|
||||
err = queue.Enqueue(2)
|
||||
assert.IsNil(err)
|
||||
|
||||
queue.Dequeue()
|
||||
queue.Dequeue()
|
||||
queue.Enqueue(6)
|
||||
queue.Enqueue(7)
|
||||
assert.Equal(2, queue.Back())
|
||||
|
||||
queue.Print()
|
||||
assert.Equal(7, queue.Back())
|
||||
val, _ := queue.Dequeue()
|
||||
assert.Equal(1, *val)
|
||||
|
||||
err = queue.Enqueue(3)
|
||||
assert.IsNil(err)
|
||||
|
||||
assert.Equal(3, queue.Back())
|
||||
}
|
||||
|
||||
func TestCircularQueue_Contain(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestCircularQueue_Contain")
|
||||
|
||||
queue := NewCircularQueue[int](2)
|
||||
queue.Enqueue(1)
|
||||
err := queue.Enqueue(1)
|
||||
assert.IsNil(err)
|
||||
|
||||
assert.Equal(true, queue.Contain(1))
|
||||
assert.Equal(false, queue.Contain(2))
|
||||
}
|
||||
@@ -115,7 +120,9 @@ func TestCircularQueue_Clear(t *testing.T) {
|
||||
assert.Equal(true, queue.IsEmpty())
|
||||
assert.Equal(0, queue.Size())
|
||||
|
||||
queue.Enqueue(1)
|
||||
err := queue.Enqueue(1)
|
||||
assert.IsNil(err)
|
||||
|
||||
assert.Equal(false, queue.IsEmpty())
|
||||
assert.Equal(1, queue.Size())
|
||||
|
||||
@@ -127,22 +134,12 @@ func TestCircularQueue_Clear(t *testing.T) {
|
||||
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 := NewCircularQueue[int](3)
|
||||
err := queue.Enqueue(1)
|
||||
assert.IsNil(err)
|
||||
|
||||
queue.Print()
|
||||
assert.Equal([]int{1, 2, 3, 4, 5}, queue.Data())
|
||||
|
||||
queue.Dequeue()
|
||||
queue.Dequeue()
|
||||
queue.Enqueue(6)
|
||||
queue.Enqueue(7)
|
||||
|
||||
queue.Print()
|
||||
assert.Equal([]int{3, 4, 5, 6, 7}, queue.Data())
|
||||
err = queue.Enqueue(2)
|
||||
assert.IsNil(err)
|
||||
|
||||
assert.Equal([]int{1, 2}, queue.Data())
|
||||
}
|
||||
|
||||
@@ -14,8 +14,6 @@ func TestLinkedQueue_Enqueue(t *testing.T) {
|
||||
queue.Enqueue(2)
|
||||
queue.Enqueue(3)
|
||||
|
||||
queue.Print()
|
||||
|
||||
assert.Equal([]int{1, 2, 3}, queue.Data())
|
||||
assert.Equal(3, queue.Size())
|
||||
}
|
||||
|
||||
@@ -23,19 +23,24 @@ func TestPriorityQueue_Enqueue(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestPriorityQueue_Enqueue")
|
||||
|
||||
comparator := &intComparator{}
|
||||
pq := NewPriorityQueue[int](10, comparator)
|
||||
pq := NewPriorityQueue[int](3, comparator)
|
||||
|
||||
assert.Equal(true, pq.IsEmpty())
|
||||
assert.Equal(false, pq.IsFull())
|
||||
|
||||
for i := 1; i < 11; i++ {
|
||||
pq.Enqueue(i)
|
||||
}
|
||||
err := pq.Enqueue(1)
|
||||
assert.IsNil(err)
|
||||
|
||||
err = pq.Enqueue(2)
|
||||
assert.IsNil(err)
|
||||
|
||||
err = pq.Enqueue(3)
|
||||
assert.IsNil(err)
|
||||
|
||||
assert.Equal(true, pq.IsFull())
|
||||
|
||||
queueData := pq.Data()
|
||||
assert.Equal([]int{10, 9, 6, 7, 8, 2, 5, 1, 4, 3}, queueData)
|
||||
assert.Equal([]int{3, 1, 2}, queueData)
|
||||
|
||||
}
|
||||
|
||||
@@ -43,22 +48,23 @@ func TestPriorityQueue_Dequeue(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestPriorityQueue_Dequeue")
|
||||
|
||||
comparator := &intComparator{}
|
||||
pq := NewPriorityQueue[int](10, comparator)
|
||||
pq := NewPriorityQueue[int](3, comparator)
|
||||
|
||||
_, ok := pq.Dequeue()
|
||||
assert.Equal(false, ok)
|
||||
|
||||
for i := 1; i < 11; i++ {
|
||||
pq.Enqueue(i)
|
||||
}
|
||||
err := pq.Enqueue(1)
|
||||
assert.IsNil(err)
|
||||
|
||||
assert.Equal(10, pq.Size())
|
||||
err = pq.Enqueue(2)
|
||||
assert.IsNil(err)
|
||||
|
||||
err = pq.Enqueue(3)
|
||||
assert.IsNil(err)
|
||||
|
||||
assert.Equal(3, 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())
|
||||
assert.Equal(3, val)
|
||||
}
|
||||
|
||||
@@ -14,8 +14,6 @@ func TestLinkedStack_Push(t *testing.T) {
|
||||
stack.Push(2)
|
||||
stack.Push(3)
|
||||
|
||||
stack.Print()
|
||||
|
||||
expected := []int{3, 2, 1}
|
||||
values := stack.Data()
|
||||
size := stack.Size()
|
||||
|
||||
@@ -27,8 +27,6 @@ func TestBSTree_Insert(t *testing.T) {
|
||||
bstree.Insert(5)
|
||||
bstree.Insert(2)
|
||||
bstree.Insert(4)
|
||||
|
||||
bstree.Print()
|
||||
}
|
||||
|
||||
func TestBSTree_PreOrderTraverse(t *testing.T) {
|
||||
@@ -86,8 +84,6 @@ func TestBSTree_LevelOrderTraverse(t *testing.T) {
|
||||
bstree.Insert(2)
|
||||
bstree.Insert(4)
|
||||
|
||||
bstree.Print()
|
||||
|
||||
acturl := bstree.LevelOrderTraverse()
|
||||
t.Log(acturl)
|
||||
assert.Equal([]int{6, 5, 7, 2, 4}, acturl)
|
||||
@@ -103,10 +99,8 @@ func TestBSTree_Delete(t *testing.T) {
|
||||
bstree.Insert(2)
|
||||
bstree.Insert(4)
|
||||
|
||||
bstree.Print()
|
||||
|
||||
bstree.Delete(4)
|
||||
bstree.Print()
|
||||
|
||||
acturl1 := bstree.InOrderTraverse()
|
||||
t.Log(acturl1)
|
||||
assert.Equal([]int{2, 5, 6, 7}, acturl1)
|
||||
@@ -129,8 +123,6 @@ func TestBSTree_Depth(t *testing.T) {
|
||||
bstree.Insert(2)
|
||||
bstree.Insert(4)
|
||||
|
||||
bstree.Print()
|
||||
|
||||
assert.Equal(bstree.Depth(), 4)
|
||||
}
|
||||
|
||||
@@ -150,8 +142,6 @@ func TestBSTree_IsSubTree(t *testing.T) {
|
||||
subTree.Insert(4)
|
||||
subTree.Insert(6)
|
||||
|
||||
subTree.Print()
|
||||
|
||||
assert.Equal(true, superTree.HasSubTree(subTree))
|
||||
assert.Equal(false, subTree.HasSubTree(superTree))
|
||||
}
|
||||
|
||||
@@ -38,35 +38,35 @@ func inOrderTraverse[T any](node *datastructure.TreeNode[T]) []T {
|
||||
return data
|
||||
}
|
||||
|
||||
func preOrderPrint[T any](node *datastructure.TreeNode[T]) {
|
||||
if node == nil {
|
||||
return
|
||||
}
|
||||
// func preOrderPrint[T any](node *datastructure.TreeNode[T]) {
|
||||
// if node == nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
fmt.Printf("%v, ", node.Value)
|
||||
preOrderPrint(node.Left)
|
||||
preOrderPrint(node.Right)
|
||||
}
|
||||
// fmt.Printf("%v, ", node.Value)
|
||||
// preOrderPrint(node.Left)
|
||||
// preOrderPrint(node.Right)
|
||||
// }
|
||||
|
||||
func postOrderPrint[T any](node *datastructure.TreeNode[T]) {
|
||||
if node == nil {
|
||||
return
|
||||
}
|
||||
// func postOrderPrint[T any](node *datastructure.TreeNode[T]) {
|
||||
// if node == nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
preOrderPrint(node.Left)
|
||||
preOrderPrint(node.Right)
|
||||
fmt.Printf("%v, ", node.Value)
|
||||
}
|
||||
// postOrderPrint(node.Left)
|
||||
// postOrderPrint(node.Right)
|
||||
// fmt.Printf("%v, ", node.Value)
|
||||
// }
|
||||
|
||||
func inOrderPrint[T any](node *datastructure.TreeNode[T]) {
|
||||
if node == nil {
|
||||
return
|
||||
}
|
||||
// func inOrderPrint[T any](node *datastructure.TreeNode[T]) {
|
||||
// if node == nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
inOrderPrint(node.Left)
|
||||
fmt.Printf("%v, ", node.Value)
|
||||
inOrderPrint(node.Right)
|
||||
}
|
||||
// inOrderPrint(node.Left)
|
||||
// fmt.Printf("%v, ", node.Value)
|
||||
// inOrderPrint(node.Right)
|
||||
// }
|
||||
|
||||
func levelOrderTraverse[T any](root *datastructure.TreeNode[T], traversal *[]T) {
|
||||
var q []*datastructure.TreeNode[T] // queue
|
||||
|
||||
@@ -570,6 +570,8 @@ func main() {
|
||||
func NewLRUCache[K comparable, V any](capacity int) *LRUCache[K, V]
|
||||
func (l *LRUCache[K, V]) Get(key K) (V, bool)
|
||||
func (l *LRUCache[K, V]) Put(key K, value V)
|
||||
func (l *LRUCache[K, V]) Delete(key K) bool
|
||||
func (l *LRUCache[K, V]) Len() int
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -586,10 +588,14 @@ func main() {
|
||||
|
||||
cache.Put(1, 1)
|
||||
cache.Put(2, 2)
|
||||
cache.Put(3, 3)
|
||||
|
||||
_, ok := cache.Get(0) // ok -> false
|
||||
fmt.Println(cache.Len()) // 3
|
||||
|
||||
v, ok := cache.Get(1) // v->1, ok->true
|
||||
v, ok := cache.Get(1)
|
||||
fmt.Println(v, ok) // 1 true
|
||||
|
||||
ok = cache.Delete(1)
|
||||
fmt.Println(ok) // true
|
||||
}
|
||||
```
|
||||
@@ -570,6 +570,8 @@ func main() {
|
||||
func NewLRUCache[K comparable, V any](capacity int) *LRUCache[K, V]
|
||||
func (l *LRUCache[K, V]) Get(key K) (V, bool)
|
||||
func (l *LRUCache[K, V]) Put(key K, value V)
|
||||
func (l *LRUCache[K, V]) Delete(key K) bool
|
||||
func (l *LRUCache[K, V]) Len() int
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -586,10 +588,14 @@ func main() {
|
||||
|
||||
cache.Put(1, 1)
|
||||
cache.Put(2, 2)
|
||||
cache.Put(3, 3)
|
||||
|
||||
_, ok := cache.Get(0) // ok -> false
|
||||
fmt.Println(cache.Len()) // 3
|
||||
|
||||
v, ok := cache.Get(1) // v->1, ok->true
|
||||
v, ok := cache.Get(1)
|
||||
fmt.Println(v, ok) // 1 true
|
||||
|
||||
ok = cache.Delete(1)
|
||||
fmt.Println(ok) // true
|
||||
}
|
||||
```
|
||||
@@ -38,13 +38,13 @@ import (
|
||||
|
||||
## Channel
|
||||
### <span id="NewChannel">NewChannel</span>
|
||||
<p>return a Channel pointer instance.</p>
|
||||
<p>Create a Channel pointer instance.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
type Channel struct {}
|
||||
func NewChannel() *Channel
|
||||
type Channel[T any] struct
|
||||
func NewChannel[T any]() *Channel[T]
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -57,7 +57,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
c := concurrency.NewChannel()
|
||||
c := concurrency.NewChannel[int]()
|
||||
}
|
||||
```
|
||||
|
||||
@@ -70,7 +70,7 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) Bridge(ctx context.Context, chanStream <-chan <-chan any) <-chan any
|
||||
func (c *Channel[T]) Bridge(ctx context.Context, chanStream <-chan <-chan T) <-chan T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -87,25 +87,30 @@ func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
genVals := func() <-chan <-chan any {
|
||||
chanStream := make(chan (<-chan any))
|
||||
c := concurrency.NewChannel[int]()
|
||||
genVals := func() <-chan <-chan int {
|
||||
out := make(chan (<-chan int))
|
||||
go func() {
|
||||
defer close(chanStream)
|
||||
for i := 0; i < 10; i++ {
|
||||
stream := make(chan any, 1)
|
||||
defer close(out)
|
||||
for i := 1; i <= 5; i++ {
|
||||
stream := make(chan int, 1)
|
||||
stream <- i
|
||||
close(stream)
|
||||
chanStream <- stream
|
||||
out <- stream
|
||||
}
|
||||
}()
|
||||
return chanStream
|
||||
return out
|
||||
}
|
||||
|
||||
index := 0
|
||||
for val := range c.Bridge(ctx, genVals()) {
|
||||
fmt.Printf("%v ", val) //0 1 2 3 4 5 6 7 8 9
|
||||
for v := range c.Bridge(ctx, genVals()) {
|
||||
fmt.Println(v)
|
||||
}
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 3
|
||||
// 4
|
||||
// 5
|
||||
}
|
||||
```
|
||||
|
||||
@@ -114,12 +119,12 @@ func main() {
|
||||
|
||||
### <span id="FanIn">FanIn</span>
|
||||
|
||||
<p>merge multiple channels into one channel until cancel the context.</p>
|
||||
<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
|
||||
func (c *Channel[T]) FanIn(ctx context.Context, channels ...<-chan T) <-chan T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -136,17 +141,17 @@ func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
channels := make([]<-chan any, 3)
|
||||
c := concurrency.NewChannel[int]()
|
||||
channels := make([]<-chan int, 2)
|
||||
|
||||
for i := 0; i < 3; i++ {
|
||||
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 3)
|
||||
for i := 0; i < 2; i++ {
|
||||
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 2)
|
||||
}
|
||||
|
||||
mergedChannel := c.FanIn(ctx, channels...)
|
||||
chs := 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)
|
||||
for v := range chs {
|
||||
fmt.Println(v) //1 1 0 0 or 0 0 1 1
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -154,12 +159,12 @@ func main() {
|
||||
|
||||
### <span id="Repeat">Repeat</span>
|
||||
|
||||
<p>Return a chan, put param `values` into the chan repeatly until cancel the context.</p>
|
||||
<p>Create channel, put values into the channel repeatly until cancel the context.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) Repeat(ctx context.Context, values ...any) <-chan any
|
||||
func (c *Channel[T]) Repeat(ctx context.Context, values ...T) <-chan T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -176,26 +181,30 @@ func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 5)
|
||||
c := concurrency.NewChannel[int]()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 4)
|
||||
|
||||
for v := range intStream {
|
||||
fmt.Println(v) //1, 2, 1, 2, 1
|
||||
fmt.Println(v)
|
||||
}
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 1
|
||||
// 2
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Generate">Generate</span>
|
||||
|
||||
### <span id="RepeatFn">RepeatFn</span>
|
||||
|
||||
<p>Return a chan, excutes fn repeatly, and put the result into retruned chan until cancel context.</p>
|
||||
<p>Creates a channel, then put values into the channel.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) RepeatFn(ctx context.Context, fn func() any) <-chan any
|
||||
func (c *Channel[T]) Generate(ctx context.Context, values ...T) <-chan T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -212,16 +221,58 @@ 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)
|
||||
c := concurrency.NewChannel[int]()
|
||||
intStream := c.Generate(ctx, 1, 2, 3)
|
||||
|
||||
for v := range dataStream {
|
||||
fmt.Println(v) //a, a, a
|
||||
fmt.Println(<-intStream)
|
||||
fmt.Println(<-intStream)
|
||||
fmt.Println(<-intStream)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 3
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RepeatFn">RepeatFn</span>
|
||||
|
||||
<p>Create a channel, excutes fn repeatly, and put the result into the channel, until close context.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel[T]) RepeatFn(ctx context.Context, fn func() T) <-chan T
|
||||
```
|
||||
<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() string {
|
||||
return "hello"
|
||||
}
|
||||
|
||||
c := concurrency.NewChannel[string]()
|
||||
intStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3)
|
||||
|
||||
for v := range intStream {
|
||||
fmt.Println(v)
|
||||
}
|
||||
// Output:
|
||||
// hello
|
||||
// hello
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
@@ -234,7 +285,7 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) Or(channels ...<-chan any) <-chan any
|
||||
func (c *Channel[T]) Or(channels ...<-chan T) <-chan T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -249,7 +300,7 @@ import (
|
||||
|
||||
func main() {
|
||||
sig := func(after time.Duration) <-chan any {
|
||||
c := make(chan interface{})
|
||||
c := make(chan any)
|
||||
go func() {
|
||||
defer close(c)
|
||||
time.Sleep(after)
|
||||
@@ -259,13 +310,11 @@ func main() {
|
||||
|
||||
start := time.Now()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
c := concurrency.NewChannel[any]()
|
||||
<-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
|
||||
@@ -282,7 +331,7 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) OrDone(ctx context.Context, channel <-chan any) <-chan any
|
||||
func (c *Channel[T]) OrDone(ctx context.Context, channel <-chan T) <-chan T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -299,12 +348,16 @@ func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
c := concurrency.NewChannel[int]()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1), 3)
|
||||
|
||||
for val := range c.OrDone(ctx, intStream) {
|
||||
fmt.Println(val) //1
|
||||
for v := range c.OrDone(ctx, intStream) {
|
||||
fmt.Println(v)
|
||||
}
|
||||
// Output:
|
||||
// 1
|
||||
// 1
|
||||
// 1
|
||||
}
|
||||
```
|
||||
|
||||
@@ -313,12 +366,12 @@ func main() {
|
||||
|
||||
### <span id="Take">Take</span>
|
||||
|
||||
<p>Return a chan whose values are tahken from another chan until cancel context.</p>
|
||||
<p>Create a channel whose values are taken from another channel with limit number.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) Take(ctx context.Context, valueStream <-chan any, number int) <-chan any
|
||||
func (c *Channel[T]) Take(ctx context.Context, valueStream <-chan T, number int) <-chan T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -335,7 +388,7 @@ func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
numbers := make(chan any, 5)
|
||||
numbers := make(chan int, 5)
|
||||
numbers <- 1
|
||||
numbers <- 2
|
||||
numbers <- 3
|
||||
@@ -343,12 +396,16 @@ func main() {
|
||||
numbers <- 5
|
||||
defer close(numbers)
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
c := concurrency.NewChannel[int]()
|
||||
intStream := c.Take(ctx, numbers, 3)
|
||||
|
||||
for val := range intStream {
|
||||
fmt.Println(val) //1, 2, 3
|
||||
for v := range intStream {
|
||||
fmt.Println(v)
|
||||
}
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 3
|
||||
}
|
||||
```
|
||||
|
||||
@@ -356,12 +413,12 @@ func main() {
|
||||
|
||||
### <span id="Tee">Tee</span>
|
||||
|
||||
<p>Split one chanel into two channels until cancel context.</p>
|
||||
<p>Split one chanel into two channels, until cancel the context.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) Tee(ctx context.Context, in <-chan any) (<-chan any, <-chan any)
|
||||
func (c *Channel[T]) Tee(ctx context.Context, in <-chan T) (<-chan T, <-chan T)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -378,13 +435,19 @@ func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
inStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 4)
|
||||
c := concurrency.NewChannel[int]()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1), 2)
|
||||
|
||||
out1, out2 := c.Tee(ctx, inStream)
|
||||
for val := range out1 {
|
||||
fmt.Println(val) //1
|
||||
fmt.Println(<-out2) //1
|
||||
ch1, ch2 := c.Tee(ctx, intStream)
|
||||
|
||||
for v := range ch1 {
|
||||
fmt.Println(v)
|
||||
fmt.Println(<-ch2)
|
||||
}
|
||||
// Output:
|
||||
// 1
|
||||
// 1
|
||||
// 1
|
||||
// 1
|
||||
}
|
||||
```
|
||||
@@ -38,13 +38,13 @@ import (
|
||||
|
||||
### Channel
|
||||
### <span id="NewChannel">NewChannel</span>
|
||||
<p>返回一个 Channel 指针实例</p>
|
||||
<p>返回一个Channel指针实例</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
type Channel struct {}
|
||||
func NewChannel() *Channel
|
||||
type Channel[T any] struct
|
||||
func NewChannel[T any]() *Channel[T]
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -57,7 +57,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
c := concurrency.NewChannel()
|
||||
c := concurrency.NewChannel[int]()
|
||||
}
|
||||
```
|
||||
|
||||
@@ -65,12 +65,12 @@ func main() {
|
||||
|
||||
### <span id="Bridge">Bridge</span>
|
||||
|
||||
<p>将多个通道链接到一个通道,直到取消上下文。</p>
|
||||
<p>将多个channel链接到一个channel,直到取消上下文。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) Bridge(ctx context.Context, chanStream <-chan <-chan any) <-chan any
|
||||
func (c *Channel[T]) Bridge(ctx context.Context, chanStream <-chan <-chan T) <-chan T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -84,28 +84,33 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
genVals := func() <-chan <-chan any {
|
||||
chanStream := make(chan (<-chan any))
|
||||
c := concurrency.NewChannel[int]()
|
||||
genVals := func() <-chan <-chan int {
|
||||
out := make(chan (<-chan int))
|
||||
go func() {
|
||||
defer close(chanStream)
|
||||
for i := 0; i < 10; i++ {
|
||||
stream := make(chan any, 1)
|
||||
defer close(out)
|
||||
for i := 1; i <= 5; i++ {
|
||||
stream := make(chan int, 1)
|
||||
stream <- i
|
||||
close(stream)
|
||||
chanStream <- stream
|
||||
out <- stream
|
||||
}
|
||||
}()
|
||||
return chanStream
|
||||
return out
|
||||
}
|
||||
|
||||
index := 0
|
||||
for val := range c.Bridge(ctx, genVals()) {
|
||||
fmt.Printf("%v ", val) //0 1 2 3 4 5 6 7 8 9
|
||||
for v := range c.Bridge(ctx, genVals()) {
|
||||
fmt.Println(v)
|
||||
}
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 3
|
||||
// 4
|
||||
// 5
|
||||
}
|
||||
```
|
||||
|
||||
@@ -114,12 +119,12 @@ func main() {
|
||||
|
||||
### <span id="FanIn">FanIn</span>
|
||||
|
||||
<p>将多个通道合并为一个通道,直到取消上下文</p>
|
||||
<p>将多个channel合并为一个channel,直到取消上下文。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) FanIn(ctx context.Context, channels ...<-chan any) <-chan any
|
||||
func (c *Channel[T]) FanIn(ctx context.Context, channels ...<-chan T) <-chan T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -133,33 +138,33 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
channels := make([]<-chan any, 3)
|
||||
c := concurrency.NewChannel[int]()
|
||||
channels := make([]<-chan int, 2)
|
||||
|
||||
for i := 0; i < 3; i++ {
|
||||
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 3)
|
||||
for i := 0; i < 2; i++ {
|
||||
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 2)
|
||||
}
|
||||
|
||||
mergedChannel := c.FanIn(ctx, channels...)
|
||||
chs := 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)
|
||||
for v := range chs {
|
||||
fmt.Println(v) //1 1 0 0 or 0 0 1 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="Repeat">Repeat</span>
|
||||
### <span id="Generate">Generate</span>
|
||||
|
||||
<p>返回一个chan,将参数`values`重复放入chan,直到取消上下文。</p>
|
||||
<p>根据传入的值,生成channel.</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) Repeat(ctx context.Context, values ...any) <-chan any
|
||||
func (c *Channel[T]) Generate(ctx context.Context, values ...T) <-chan T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -173,15 +178,58 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 5)
|
||||
c := concurrency.NewChannel[int]()
|
||||
intStream := c.Generate(ctx, 1, 2, 3)
|
||||
|
||||
fmt.Println(<-intStream)
|
||||
fmt.Println(<-intStream)
|
||||
fmt.Println(<-intStream)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 3
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Repeat">Repeat</span>
|
||||
|
||||
<p>返回一个channel,将参数`values`重复放入channel,直到取消上下文。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel[T]) Repeat(ctx context.Context, values ...T) <-chan T
|
||||
```
|
||||
<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[int]()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 4)
|
||||
|
||||
for v := range intStream {
|
||||
fmt.Println(v) //1, 2, 1, 2, 1
|
||||
fmt.Println(v)
|
||||
}
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 1
|
||||
// 2
|
||||
}
|
||||
```
|
||||
|
||||
@@ -190,12 +238,12 @@ func main() {
|
||||
|
||||
### <span id="RepeatFn">RepeatFn</span>
|
||||
|
||||
<p>返回一个chan,重复执行函数fn,并将结果放入返回的chan,直到取消上下文。</p>
|
||||
<p>返回一个channel,重复执行函数fn,并将结果放入返回的channel,直到取消上下文。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) RepeatFn(ctx context.Context, fn func() any) <-chan any
|
||||
func (c *Channel[T]) RepeatFn(ctx context.Context, fn func() T) <-chan T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -209,19 +257,23 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
fn := func() any {
|
||||
s := "a"
|
||||
return s
|
||||
fn := func() string {
|
||||
return "hello"
|
||||
}
|
||||
c := concurrency.NewChannel()
|
||||
dataStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3)
|
||||
|
||||
for v := range dataStream {
|
||||
fmt.Println(v) //a, a, a
|
||||
c := concurrency.NewChannel[string]()
|
||||
intStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3)
|
||||
|
||||
for v := range intStream {
|
||||
fmt.Println(v)
|
||||
}
|
||||
// Output:
|
||||
// hello
|
||||
// hello
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
@@ -229,12 +281,12 @@ func main() {
|
||||
|
||||
### <span id="Or">Or</span>
|
||||
|
||||
<p>将一个或多个通道读取到一个通道中,当任何读取通道关闭时将结束读取。</p>
|
||||
<p>将一个或多个channel读取到一个channel中,当任何读取channel关闭时将结束读取。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) Or(channels ...<-chan any) <-chan any
|
||||
func (c *Channel[T]) Or(channels ...<-chan T) <-chan T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -249,7 +301,7 @@ import (
|
||||
|
||||
func main() {
|
||||
sig := func(after time.Duration) <-chan any {
|
||||
c := make(chan interface{})
|
||||
c := make(chan any)
|
||||
go func() {
|
||||
defer close(c)
|
||||
time.Sleep(after)
|
||||
@@ -259,13 +311,11 @@ func main() {
|
||||
|
||||
start := time.Now()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
c := concurrency.NewChannel[any]()
|
||||
<-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
|
||||
@@ -277,12 +327,12 @@ func main() {
|
||||
|
||||
### <span id="OrDone">OrDone</span>
|
||||
|
||||
<p>将一个通道读入另一个通道,直到取消上下文。</p>
|
||||
<p>将一个channel读入另一个channel,直到取消上下文。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) OrDone(ctx context.Context, channel <-chan any) <-chan any
|
||||
func (c *Channel[T]) OrDone(ctx context.Context, channel <-chan T) <-chan T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -299,12 +349,16 @@ func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
c := concurrency.NewChannel[int]()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1), 3)
|
||||
|
||||
for val := range c.OrDone(ctx, intStream) {
|
||||
fmt.Println(val) //1
|
||||
for v := range c.OrDone(ctx, intStream) {
|
||||
fmt.Println(v)
|
||||
}
|
||||
// Output:
|
||||
// 1
|
||||
// 1
|
||||
// 1
|
||||
}
|
||||
```
|
||||
|
||||
@@ -313,12 +367,12 @@ func main() {
|
||||
|
||||
### <span id="Take">Take</span>
|
||||
|
||||
<p>返回一个chan,其值从另一个chan获取,直到取消上下文。</p>
|
||||
<p>返回一个channel,其值从另一个channel获取,直到取消上下文。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) Take(ctx context.Context, valueStream <-chan any, number int) <-chan any
|
||||
func (c *Channel[T]) Take(ctx context.Context, valueStream <-chan T, number int) <-chan T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -335,7 +389,7 @@ func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
numbers := make(chan any, 5)
|
||||
numbers := make(chan int, 5)
|
||||
numbers <- 1
|
||||
numbers <- 2
|
||||
numbers <- 3
|
||||
@@ -343,12 +397,16 @@ func main() {
|
||||
numbers <- 5
|
||||
defer close(numbers)
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
c := concurrency.NewChannel[int]()
|
||||
intStream := c.Take(ctx, numbers, 3)
|
||||
|
||||
for val := range intStream {
|
||||
fmt.Println(val) //1, 2, 3
|
||||
for v := range intStream {
|
||||
fmt.Println(v)
|
||||
}
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 3
|
||||
}
|
||||
```
|
||||
|
||||
@@ -356,12 +414,12 @@ func main() {
|
||||
|
||||
### <span id="Tee">Tee</span>
|
||||
|
||||
<p>将一个通道分成两个通道,直到取消上下文。</p>
|
||||
<p>将一个channel分成两个channel,直到取消上下文。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) Tee(ctx context.Context, in <-chan any) (<-chan any, <-chan any)
|
||||
func (c *Channel[T]) Tee(ctx context.Context, in <-chan T) (<-chan T, <-chan T)
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -378,13 +436,19 @@ func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
inStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 4)
|
||||
c := concurrency.NewChannel[int]()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1), 2)
|
||||
|
||||
out1, out2 := c.Tee(ctx, inStream)
|
||||
for val := range out1 {
|
||||
fmt.Println(val) //1
|
||||
fmt.Println(<-out2) //1
|
||||
ch1, ch2 := c.Tee(ctx, intStream)
|
||||
|
||||
for v := range ch1 {
|
||||
fmt.Println(v)
|
||||
fmt.Println(<-ch2)
|
||||
}
|
||||
// Output:
|
||||
// 1
|
||||
// 1
|
||||
// 1
|
||||
// 1
|
||||
}
|
||||
```
|
||||
@@ -25,6 +25,7 @@ import (
|
||||
- [Or](#Or)
|
||||
- [Xor](#Generate)
|
||||
- [Nor](#Nor)
|
||||
- [Xnor](#Xnor)
|
||||
- [Nand](#Nand)
|
||||
- [TernaryOperator](#TernaryOperator)
|
||||
|
||||
@@ -120,7 +121,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="Or">Or</span>
|
||||
<p>Returns false iff neither a nor b is truthy.</p>
|
||||
<p>Returns false if neither a nor b is truthy.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -148,7 +149,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="Xor">Xor</span>
|
||||
<p>Returns true iff a or b but not both is truthy.</p>
|
||||
<p>Returns true if a or b but not both is truthy.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -176,7 +177,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="Nor">Nor</span>
|
||||
<p>Returns true iff neither a nor b is truthy.</p>
|
||||
<p>Returns true if neither a nor b is truthy.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -197,14 +198,40 @@ func main() {
|
||||
fmt.Println(condition.Nor(0, 0)) // true
|
||||
fmt.Println(condition.Nor(0, 1)) // false
|
||||
fmt.Println(condition.Nor(1, 0)) // false
|
||||
fmt.Println(condition.Nor(1, 1)) // true
|
||||
fmt.Println(condition.Nor(1, 1)) // false
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="Xnor">Xnor</span>
|
||||
<p>Returns true if both a and b or neither a nor b are truthy.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Xnor[T, U any](a T, b U) bool
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/condition"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(condition.Xnor(0, 0)) // true
|
||||
fmt.Println(condition.Xnor(0, 1)) // false
|
||||
fmt.Println(condition.Xnor(1, 0)) // false
|
||||
fmt.Println(condition.Xnor(1, 1)) // true
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="Nand">Nand</span>
|
||||
<p>Returns false iff both a and b are truthy</p>
|
||||
<p>Returns false if both a and b are truthy</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ import (
|
||||
- [Or](#Or)
|
||||
- [Xor](#Generate)
|
||||
- [Nor](#Nor)
|
||||
- [Xnor](#Xnor)
|
||||
- [Nand](#Nand)
|
||||
- [TernaryOperator](#TernaryOperator)
|
||||
|
||||
@@ -196,12 +197,38 @@ func main() {
|
||||
fmt.Println(condition.Nor(0, 0)) // true
|
||||
fmt.Println(condition.Nor(0, 1)) // false
|
||||
fmt.Println(condition.Nor(1, 0)) // false
|
||||
fmt.Println(condition.Nor(1, 1)) // true
|
||||
fmt.Println(condition.Nor(1, 1)) // false
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Xnor">Xnor</span>
|
||||
<p>如果a和b都是真的或a和b均是假的,则返回true。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Xnor[T, U any](a T, b U) bool
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/condition"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(condition.Xnor(0, 0)) // true
|
||||
fmt.Println(condition.Xnor(0, 1)) // false
|
||||
fmt.Println(condition.Xnor(1, 0)) // false
|
||||
fmt.Println(condition.Xnor(1, 1)) // true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Nand">Nand</span>
|
||||
<p>如果a和b都为真,返回false,否则返回true</p>
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ func main() {
|
||||
|
||||
### <span id="ToBool">ToBool</span>
|
||||
|
||||
<p>Convert string to a boolean value. Use strconv.ParseBool</p>
|
||||
<p>Convert string to bool. Use strconv.ParseBool.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -138,7 +138,7 @@ func main() {
|
||||
|
||||
### <span id="ToBytes">ToBytes</span>
|
||||
|
||||
<p>Convert interface to byte slice.</p>
|
||||
<p>Convert value to byte slice.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -200,7 +200,7 @@ func main() {
|
||||
|
||||
### <span id="ToChannel">ToChannel</span>
|
||||
|
||||
<p>Convert a collection of elements to a read-only channels.</p>
|
||||
<p>Convert a collection of elements to a read-only channel.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -238,7 +238,7 @@ func main() {
|
||||
|
||||
### <span id="ToFloat">ToFloat</span>
|
||||
|
||||
<p>Convert interface to a float64 value. If param is a invalid floatable, will return 0 and error. </p>
|
||||
<p>Convert value to a float64 value. If param is a invalid floatable, will return 0.0 and error. </p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -271,7 +271,7 @@ func main() {
|
||||
|
||||
### <span id="ToInt">ToInt</span>
|
||||
|
||||
<p>Convert interface to a int64 value. If param is a invalid intable, will return 0 and error. </p>
|
||||
<p>Convert value to a int64 value. If param is a invalid intable, will return 0 and error. </p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -332,7 +332,7 @@ func main() {
|
||||
|
||||
### <span id="ToMap">ToMap</span>
|
||||
|
||||
<p>Convert a slice or an array of structs to a map based on iteratee function. </p>
|
||||
<p>Convert a slice of structs to a map based on iteratee function. </p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
|
||||
@@ -522,7 +522,7 @@ func main() {
|
||||
|
||||
### <span id="DecodeByte">DecodeByte</span>
|
||||
|
||||
<p>解码字节切片到目标对象,目标对象需要传入一个指针实例子</p>
|
||||
<p>解码字节切片到目标对象,目标对象需要传入一个指针实例</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
|
||||
@@ -132,12 +132,12 @@ func main() {
|
||||
|
||||
|
||||
### <span id="SinglyLink_InsertAt">InsertAt</span>
|
||||
<p>Insert value into singly linklist at index, index shoud be great or equal 0 and less or equal number of link nodes</p>
|
||||
<p>Insert value into singly linklist at index, param `index` should between [0, len(SinglyLink)], if index do not meet the conditions, do nothing</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (link *SinglyLink[T]) InsertAt(index int, value T) error
|
||||
func (link *SinglyLink[T]) InsertAt(index int, value T)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -152,6 +152,8 @@ import (
|
||||
func main() {
|
||||
lk := link.NewSinglyLink[int]()
|
||||
|
||||
lk.InsertAt(1, 1) //do nothing
|
||||
|
||||
lk.InsertAt(0, 1)
|
||||
lk.InsertAt(1, 2)
|
||||
lk.InsertAt(2, 3)
|
||||
@@ -228,12 +230,12 @@ func main() {
|
||||
|
||||
|
||||
### <span id="SinglyLink_DeleteAt">DeleteAt</span>
|
||||
<p>Delete value at specific index, index shoud be great or equal 0 and less or less than number of link nodes - 1</p>
|
||||
<p>Delete value at specific index, param `index` should be [0, len(SinglyLink)-1]</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (link *SinglyLink[T]) DeleteAt(index int) error
|
||||
func (link *SinglyLink[T]) DeleteAt(index int)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -253,9 +255,8 @@ func main() {
|
||||
lk.InsertAtTail(3)
|
||||
lk.InsertAtTail(4)
|
||||
|
||||
err := lk.DeleteAt(3)
|
||||
lk.DeleteAt(3)
|
||||
|
||||
fmt.Println(err) //nil
|
||||
fmt.Println(lk.Values()) //[]int{1, 2, 3}
|
||||
}
|
||||
```
|
||||
@@ -268,7 +269,7 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (link *SinglyLink[T]) DeleteAtHead() error
|
||||
func (link *SinglyLink[T]) DeleteAtHead()
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -288,9 +289,8 @@ func main() {
|
||||
lk.InsertAtTail(3)
|
||||
lk.InsertAtTail(4)
|
||||
|
||||
err := lk.DeleteAtHead()
|
||||
lk.DeleteAtHead()
|
||||
|
||||
fmt.Println(err) //nil
|
||||
fmt.Println(lk.Values()) //[]int{2, 3, 4}
|
||||
}
|
||||
```
|
||||
@@ -304,7 +304,7 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (link *SinglyLink[T]) DeleteAtTail() error
|
||||
func (link *SinglyLink[T]) DeleteAtTail()
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -323,9 +323,8 @@ func main() {
|
||||
lk.InsertAtTail(2)
|
||||
lk.InsertAtTail(3)
|
||||
|
||||
err := lk.DeleteAtTail()
|
||||
lk.DeleteAtTail()
|
||||
|
||||
fmt.Println(err) //nil
|
||||
fmt.Println(lk.Values()) //[]int{1, 2}
|
||||
}
|
||||
```
|
||||
@@ -628,12 +627,12 @@ func main() {
|
||||
|
||||
|
||||
### <span id="DoublyLink_InsertAt">InsertAt</span>
|
||||
<p>Insert value into doubly linklist at index, index shoud be great or equal 0 and less or equal number of link nodes</p>
|
||||
<p>Insert value into doubly linklist at index, param `index` should between [0, len(DoublyLink)], if index do not meet the conditions, do nothing</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (link *DoublyLink[T]) InsertAt(index int, value T) error
|
||||
func (link *DoublyLink[T]) InsertAt(index int, value T)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -648,6 +647,8 @@ import (
|
||||
func main() {
|
||||
lk := link.NewDoublyLink[int]()
|
||||
|
||||
lk.InsertAt(1, 1) //do nothing
|
||||
|
||||
lk.InsertAt(0, 1)
|
||||
lk.InsertAt(1, 2)
|
||||
lk.InsertAt(2, 3)
|
||||
@@ -724,12 +725,12 @@ func main() {
|
||||
|
||||
|
||||
### <span id="DoublyLink_DeleteAt">DeleteAt</span>
|
||||
<p>Delete value at specific index, index shoud be great or equal 0 and less or less than number of link nodes - 1</p>
|
||||
<p>Delete value at specific index, param `index` should be [0, len(DoublyLink)-1]</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (link *DoublyLink[T]) DeleteAt(index int) error
|
||||
func (link *DoublyLink[T]) DeleteAt(index int)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -749,9 +750,8 @@ func main() {
|
||||
lk.InsertAtTail(3)
|
||||
lk.InsertAtTail(4)
|
||||
|
||||
err := lk.DeleteAt(3)
|
||||
lk.DeleteAt(3)
|
||||
|
||||
fmt.Println(err) //nil
|
||||
fmt.Println(lk.Values()) //[]int{1, 2, 3}
|
||||
}
|
||||
```
|
||||
@@ -764,7 +764,7 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (link *DoublyLink[T]) DeleteAtHead() error
|
||||
func (link *DoublyLink[T]) DeleteAtHead()
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -784,9 +784,8 @@ func main() {
|
||||
lk.InsertAtTail(3)
|
||||
lk.InsertAtTail(4)
|
||||
|
||||
err := lk.DeleteAtHead()
|
||||
lk.DeleteAtHead()
|
||||
|
||||
fmt.Println(err) //nil
|
||||
fmt.Println(lk.Values()) //[]int{2, 3, 4}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -132,12 +132,12 @@ func main() {
|
||||
|
||||
|
||||
### <span id="SinglyLink_InsertAt">InsertAt</span>
|
||||
<p>将值插入到索引处的链表中,索引应大于或等于 0 且小于或等于链表节点数</p>
|
||||
<p>将值插入到索引处的链表中,索引应大于或等于0且小于或等于链表节点数</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (link *SinglyLink[T]) InsertAt(index int, value T) error
|
||||
func (link *SinglyLink[T]) InsertAt(index int, value T)
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -152,6 +152,8 @@ import (
|
||||
func main() {
|
||||
lk := link.NewSinglyLink[int]()
|
||||
|
||||
lk.InsertAt(1, 1) //do nothing
|
||||
|
||||
lk.InsertAt(0, 1)
|
||||
lk.InsertAt(1, 2)
|
||||
lk.InsertAt(2, 3)
|
||||
@@ -228,12 +230,12 @@ func main() {
|
||||
|
||||
|
||||
### <span id="SinglyLink_DeleteAt">DeleteAt</span>
|
||||
<p>删除特定索引处的值,索引应大于或等于0且小于或等于链接节点数 - 1</p>
|
||||
<p>删除特定索引处的值,索引应大于或等于0且小于或等于链接节点数-1</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (link *SinglyLink[T]) DeleteAt(index int) error
|
||||
func (link *SinglyLink[T]) DeleteAt(index int)
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -253,9 +255,8 @@ func main() {
|
||||
lk.InsertAtTail(3)
|
||||
lk.InsertAtTail(4)
|
||||
|
||||
err := lk.DeleteAt(3)
|
||||
lk.DeleteAt(3)
|
||||
|
||||
fmt.Println(err) //nil
|
||||
fmt.Println(lk.Values()) //[]int{1, 2, 3}
|
||||
}
|
||||
```
|
||||
@@ -268,7 +269,7 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (link *SinglyLink[T]) DeleteAtHead() error
|
||||
func (link *SinglyLink[T]) DeleteAtHead()
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -288,9 +289,8 @@ func main() {
|
||||
lk.InsertAtTail(3)
|
||||
lk.InsertAtTail(4)
|
||||
|
||||
err := lk.DeleteAtHead()
|
||||
lk.DeleteAtHead()
|
||||
|
||||
fmt.Println(err) //nil
|
||||
fmt.Println(lk.Values()) //[]int{2, 3, 4}
|
||||
}
|
||||
```
|
||||
@@ -304,7 +304,7 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (link *SinglyLink[T]) DeleteAtTail() error
|
||||
func (link *SinglyLink[T]) DeleteAtTail()
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -323,9 +323,8 @@ func main() {
|
||||
lk.InsertAtTail(2)
|
||||
lk.InsertAtTail(3)
|
||||
|
||||
err := lk.DeleteAtTail()
|
||||
lk.DeleteAtTail()
|
||||
|
||||
fmt.Println(err) //nil
|
||||
fmt.Println(lk.Values()) //[]int{1, 2}
|
||||
}
|
||||
```
|
||||
@@ -628,12 +627,12 @@ func main() {
|
||||
|
||||
|
||||
### <span id="DoublyLink_InsertAt">InsertAt</span>
|
||||
<p>将值插入到索引处的链表中,索引应大于或等于 0 且小于或等于链表节点数</p>
|
||||
<p>将值插入到索引处的链表中,索引应大于或等于0且小于或等于链表节点数</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (link *DoublyLink[T]) InsertAt(index int, value T) error
|
||||
func (link *DoublyLink[T]) InsertAt(index int, value T)
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -648,6 +647,8 @@ import (
|
||||
func main() {
|
||||
lk := link.NewDoublyLink[int]()
|
||||
|
||||
lk.InsertAt(1, 1) //do nothing
|
||||
|
||||
lk.InsertAt(0, 1)
|
||||
lk.InsertAt(1, 2)
|
||||
lk.InsertAt(2, 3)
|
||||
@@ -724,12 +725,12 @@ func main() {
|
||||
|
||||
|
||||
### <span id="DoublyLink_DeleteAt">DeleteAt</span>
|
||||
<p>删除特定索引处的值,索引应大于或等于0且小于或等于链接节点数 - 1</p>
|
||||
<p>删除特定索引处的值,索引应大于或等于0且小于或等于链接节点数-1</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (link *DoublyLink[T]) DeleteAt(index int) error
|
||||
func (link *DoublyLink[T]) DeleteAt(index int)
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -749,9 +750,8 @@ func main() {
|
||||
lk.InsertAtTail(3)
|
||||
lk.InsertAtTail(4)
|
||||
|
||||
err := lk.DeleteAt(3)
|
||||
lk.DeleteAt(3)
|
||||
|
||||
fmt.Println(err) //nil
|
||||
fmt.Println(lk.Values()) //[]int{1, 2, 3}
|
||||
}
|
||||
```
|
||||
@@ -764,7 +764,7 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (link *DoublyLink[T]) DeleteAtHead() error
|
||||
func (link *DoublyLink[T]) DeleteAtHead()
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -784,9 +784,8 @@ func main() {
|
||||
lk.InsertAtTail(3)
|
||||
lk.InsertAtTail(4)
|
||||
|
||||
err := lk.DeleteAtHead()
|
||||
lk.DeleteAtHead()
|
||||
|
||||
fmt.Println(err) //nil
|
||||
fmt.Println(lk.Values()) //[]int{2, 3, 4}
|
||||
}
|
||||
```
|
||||
@@ -800,7 +799,7 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (link *DoublyLink[T]) DeleteAtTail() error
|
||||
func (link *DoublyLink[T]) DeleteAtTail()
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -819,9 +818,8 @@ func main() {
|
||||
lk.InsertAtTail(2)
|
||||
lk.InsertAtTail(3)
|
||||
|
||||
err := lk.DeleteAtTail()
|
||||
lk.DeleteAtTail()
|
||||
|
||||
fmt.Println(err) //nil
|
||||
fmt.Println(lk.Values()) //[]int{1, 2}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -119,7 +119,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="CopyFile">CopyFile</span>
|
||||
<p>拷贝文件,会覆盖原有的拷贝文件</p>
|
||||
<p>拷贝文件,会覆盖原有的文件</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -261,7 +261,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="IsDir">IsDir</span>
|
||||
<p>判断目录是否存在</p>
|
||||
<p>判断参数是否是目录</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
|
||||
@@ -28,13 +28,12 @@ import (
|
||||
|
||||
|
||||
### <span id="Comma">Comma</span>
|
||||
<p>Add comma to number by every 3 numbers from right. ahead by symbol char.
|
||||
Param should be number or numberic string.</p>
|
||||
<p>Add comma to a number value by every 3 numbers from right to left. ahead by symbol char. if value is a invalid number string like "aa", return empty string.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Comma(v any, symbol string) string
|
||||
func Comma[T constraints.Float | constraints.Integer | string](value T, symbol string) string
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
|
||||
@@ -28,12 +28,12 @@ import (
|
||||
|
||||
|
||||
### <span id="Comma">Comma</span>
|
||||
<p>用逗号每隔3位分割数字/字符串,签名添加符号。参数必须是数字或者可以转为数字的字符串</p>
|
||||
<p>用逗号每隔3位分割数字/字符串,支持前缀添加符号。参数value必须是数字或者可以转为数字的字符串, 否则返回空字符串</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Comma(v any, symbol string) string
|
||||
func Comma[T constraints.Float | constraints.Integer | string](value T, symbol string) string
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
## Index
|
||||
- [After](#After)
|
||||
- [Before](#Before)
|
||||
- [Curry](#Curry)
|
||||
- [CurryFn](#CurryFn)
|
||||
- [Compose](#Compose)
|
||||
- [Debounced](#Debounced)
|
||||
- [Delay](#Delay)
|
||||
@@ -125,15 +125,15 @@ func main() {
|
||||
|
||||
|
||||
|
||||
### <span id="Curry">Curry</span>
|
||||
### <span id="CurryFn">CurryFn</span>
|
||||
|
||||
<p>Make a curry function.</p>
|
||||
<p>Make curry function.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
type Fn func(...any) any
|
||||
func (f Fn) Curry(i any) func(...any) any
|
||||
type CurryFn[T any] func(...T) T
|
||||
func (cf CurryFn[T]) New(val T) func(...T) T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -149,12 +149,15 @@ func main() {
|
||||
add := func(a, b int) int {
|
||||
return a + b
|
||||
}
|
||||
var addCurry function.Fn = func(values ...any) any {
|
||||
return add(values[0].(int), values[1].(int))
|
||||
|
||||
var addCurry CurryFn[int] = func(values ...int) int {
|
||||
return add(values[0], values[1])
|
||||
}
|
||||
add1 := addCurry.Curry(1)
|
||||
add1 := addCurry.New(1)
|
||||
|
||||
result := add1(2)
|
||||
fmt.Println(result) //3
|
||||
|
||||
fmt.Println(result) //3
|
||||
}
|
||||
```
|
||||
|
||||
@@ -167,7 +170,7 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Compose(fnList ...func(...any) any) func(...any) any
|
||||
func Compose[T any](fnList ...func(...T) T) func(...T) T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -180,17 +183,17 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
add1 := func(v ...any) any {
|
||||
return v[0].(int) + 1
|
||||
toUpper := func(strs ...string) string {
|
||||
return strings.ToUpper(strs[0])
|
||||
}
|
||||
add2 := func(v ...any) any {
|
||||
return v[0].(int) + 2
|
||||
toLower := func(strs ...string) string {
|
||||
return strings.ToLower(strs[0])
|
||||
}
|
||||
transform := Compose(toUpper, toLower)
|
||||
|
||||
add3 := function.Compose(add1, add2)
|
||||
result := add3(1)
|
||||
result := transform("aBCde")
|
||||
|
||||
fmt.Println(result) //4
|
||||
fmt.Println(result) //ABCDE
|
||||
}
|
||||
```
|
||||
|
||||
@@ -259,9 +262,9 @@ import (
|
||||
|
||||
func main() {
|
||||
var print = func(s string) {
|
||||
fmt.Println(count) //test delay
|
||||
fmt.Println(count) //delay 2 seconds
|
||||
}
|
||||
function.Delay(2*time.Second, print, "test delay")
|
||||
function.Delay(2*time.Second, print, "delay 2 seconds")
|
||||
}
|
||||
```
|
||||
|
||||
@@ -332,9 +335,9 @@ func main() {
|
||||
return x * x
|
||||
}
|
||||
|
||||
f := Pipeline(addOne, double, square)
|
||||
fn := Pipeline(addOne, double, square)
|
||||
|
||||
fmt.Println(f(2)) //36
|
||||
fmt.Println(fn(2)) //36
|
||||
}
|
||||
```
|
||||
|
||||
@@ -351,6 +354,7 @@ type Watcher struct {
|
||||
stopTime int64
|
||||
excuting bool
|
||||
}
|
||||
func NewWatcher() *Watcher
|
||||
func (w *Watcher) Start() //start the watcher
|
||||
func (w *Watcher) Stop() //stop the watcher
|
||||
func (w *Watcher) Reset() //reset the watcher
|
||||
@@ -367,7 +371,8 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
w := &function.Watcher{}
|
||||
w := function.NewWatcher()
|
||||
|
||||
w.Start()
|
||||
|
||||
longRunningTask()
|
||||
@@ -377,14 +382,10 @@ func main() {
|
||||
w.Stop()
|
||||
|
||||
eapsedTime := w.GetElapsedTime().Milliseconds()
|
||||
|
||||
fmt.Println(eapsedTime)
|
||||
|
||||
w.Reset()
|
||||
|
||||
fmt.Println(w.excuting) //false
|
||||
|
||||
fmt.Println(w.startTime) //0
|
||||
fmt.Println(w.stopTime) //0
|
||||
}
|
||||
|
||||
func longRunningTask() {
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
## 目录
|
||||
- [After](#After)
|
||||
- [Before](#Before)
|
||||
- [Curry](#Curry)
|
||||
- [CurryFn](#CurryFn)
|
||||
- [Compose](#Compose)
|
||||
- [Debounced](#Debounced)
|
||||
- [Delay](#Delay)
|
||||
@@ -124,15 +124,15 @@ func main() {
|
||||
|
||||
|
||||
|
||||
### <span id="Curry">Curry</span>
|
||||
### <span id="CurryFn">CurryFn</span>
|
||||
|
||||
<p>创建一个柯里化的函数</p>
|
||||
<p>创建柯里化函数</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
type Fn func(...any) any
|
||||
func (f Fn) Curry(i any) func(...any) any
|
||||
type CurryFn[T any] func(...T) T
|
||||
func (cf CurryFn[T]) New(val T) func(...T) T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -148,11 +148,14 @@ func main() {
|
||||
add := func(a, b int) int {
|
||||
return a + b
|
||||
}
|
||||
var addCurry function.Fn = func(values ...any) any {
|
||||
return add(values[0].(int), values[1].(int))
|
||||
|
||||
var addCurry CurryFn[int] = func(values ...int) int {
|
||||
return add(values[0], values[1])
|
||||
}
|
||||
add1 := addCurry.Curry(1)
|
||||
add1 := addCurry.New(1)
|
||||
|
||||
result := add1(2)
|
||||
|
||||
fmt.Println(result) //3
|
||||
}
|
||||
```
|
||||
@@ -161,12 +164,12 @@ func main() {
|
||||
|
||||
### <span id="Compose">Compose</span>
|
||||
|
||||
<p>从右至左组合函数列表fnList, 返回组合后的函数</p>
|
||||
<p>从右至左组合函数列表fnList,返回组合后的函数</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Compose(fnList ...func(...any) any) func(...any) any
|
||||
func Compose[T any](fnList ...func(...T) T) func(...T) T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -179,17 +182,17 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
add1 := func(v ...any) any {
|
||||
return v[0].(int) + 1
|
||||
toUpper := func(strs ...string) string {
|
||||
return strings.ToUpper(strs[0])
|
||||
}
|
||||
add2 := func(v ...any) any {
|
||||
return v[0].(int) + 2
|
||||
toLower := func(strs ...string) string {
|
||||
return strings.ToLower(strs[0])
|
||||
}
|
||||
transform := Compose(toUpper, toLower)
|
||||
|
||||
add3 := function.Compose(add1, add2)
|
||||
result := add3(1)
|
||||
result := transform("aBCde")
|
||||
|
||||
fmt.Println(result) //4
|
||||
fmt.Println(result) //ABCDE
|
||||
}
|
||||
```
|
||||
|
||||
@@ -197,7 +200,7 @@ func main() {
|
||||
|
||||
### <span id="Debounced">Debounced</span>
|
||||
|
||||
<p>创建一个 debounced 函数,该函数延迟调用 fn 直到自上次调用 debounced 函数后等待持续时间过去。</p>
|
||||
<p>创建一个debounced函数,该函数延迟调用fn直到自上次调用debounced函数后等待持续时间过去。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -333,7 +336,7 @@ func main() {
|
||||
|
||||
f := Pipeline(addOne, double, square)
|
||||
|
||||
fmt.Println(f(2)) //36
|
||||
fmt.Println(fn(2)) //36
|
||||
}
|
||||
```
|
||||
|
||||
@@ -341,7 +344,7 @@ func main() {
|
||||
|
||||
### <span id="Watcher">Watcher</span>
|
||||
|
||||
<p>Watcher 用于记录代码执行时间。可以启动/停止/重置手表定时器。获取函数执行的时间。 </p>
|
||||
<p>Watcher用于记录代码执行时间。可以启动/停止/重置手表定时器。获取函数执行的时间。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -351,6 +354,7 @@ type Watcher struct {
|
||||
stopTime int64
|
||||
excuting bool
|
||||
}
|
||||
func NewWatcher() *Watcher
|
||||
func (w *Watcher) Start() //start the watcher
|
||||
func (w *Watcher) Stop() //stop the watcher
|
||||
func (w *Watcher) Reset() //reset the watcher
|
||||
@@ -367,7 +371,8 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
w := &function.Watcher{}
|
||||
w := function.NewWatcher()
|
||||
|
||||
w.Start()
|
||||
|
||||
longRunningTask()
|
||||
@@ -377,14 +382,11 @@ func main() {
|
||||
w.Stop()
|
||||
|
||||
eapsedTime := w.GetElapsedTime().Milliseconds()
|
||||
|
||||
fmt.Println(eapsedTime)
|
||||
|
||||
w.Reset()
|
||||
|
||||
fmt.Println(w.excuting) //false
|
||||
|
||||
fmt.Println(w.startTime) //0
|
||||
fmt.Println(w.stopTime) //0
|
||||
}
|
||||
|
||||
func longRunningTask() {
|
||||
|
||||
@@ -45,7 +45,7 @@ import (
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Average[T lancetconstraints.Number](numbers ...T) T
|
||||
func Average[T constraints.Integer | constraints.Float](numbers ...T) T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -157,7 +157,7 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Max[T lancetconstraints.Number](numbers ...T) T
|
||||
func Max[T constraints.Integer | constraints.Float](numbers ...T) T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -218,12 +218,12 @@ func main() {
|
||||
|
||||
|
||||
### <span id="Min">Min</span>
|
||||
<p>Return min value of numbers.</p>
|
||||
<p>Return the minimum value of numbers.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Min[T lancetconstraints.Number](numbers ...T) T
|
||||
func Min[T constraints.Integer | constraints.Float](numbers ...T) T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -302,8 +302,8 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.Percent(1, 2, 2)) //1
|
||||
fmt.Println(mathutil.Percent(0.1, 0.3, 2)) //33.33
|
||||
fmt.Println(mathutil.Percent(1, 2, 2)) //0.5
|
||||
fmt.Println(mathutil.Percent(0.1, 0.3, 2)) //0.33
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ import (
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Average[T lancetconstraints.Number](numbers ...T) T
|
||||
func Average[T constraints.Integer | constraints.Float](numbers ...T) T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -154,7 +154,7 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Max[T lancetconstraints.Number](numbers ...T) T
|
||||
func Max[T constraints.Integer | constraints.Float](numbers ...T) T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -220,7 +220,7 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Min[T lancetconstraints.Number](numbers ...T) T
|
||||
func Min[T constraints.Integer | constraints.Float](numbers ...T) T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -299,8 +299,8 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.Percent(1, 2, 2)) //1
|
||||
fmt.Println(mathutil.Percent(0.1, 0.3, 2)) //33.33
|
||||
fmt.Println(mathutil.Percent(1, 2, 2)) //0.5
|
||||
fmt.Println(mathutil.Percent(0.1, 0.3, 2)) //0.33
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -1138,7 +1138,7 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Sort[T lancetconstraints.Ordered](slice []T, sortOrder ...string)
|
||||
func Sort[T constraints.Ordered](slice []T, sortOrder ...string)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -319,7 +319,7 @@ func main() {
|
||||
|
||||
### <span id="DifferenceBy">DifferenceBy</span>
|
||||
|
||||
<p>在slice和comparedSlice中的每个元素调用iteratee函数,并比较它们的返回值,如果不想等返回在slice中对应的值</p>
|
||||
<p>将两个slice中的每个元素调用iteratee函数,并比较它们的返回值,如果不相等返回在slice中对应的值</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -349,7 +349,7 @@ func main() {
|
||||
|
||||
### <span id="DifferenceWith">DifferenceWith</span>
|
||||
|
||||
<p>DifferenceWith 接受比较器,该比较器被调用以将切片的元素与值进行比较。 结果值的顺序和引用由第一个切片确定</p>
|
||||
<p>接受比较器函数,该比较器被调用以将切片的元素与值进行比较。 结果值的顺序和引用由第一个切片确定</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -379,7 +379,7 @@ func main() {
|
||||
|
||||
### <span id="DeleteAt">DeleteAt</span>
|
||||
|
||||
<p>删除切片中从开始索引到结束索引-1的元素</p>
|
||||
<p>删除切片中指定开始索引到结束索引的元素</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -407,7 +407,7 @@ func main() {
|
||||
|
||||
### <span id="Drop">Drop</span>
|
||||
|
||||
<p>创建一个切片,当 n > 0 时从开头删除 n 个元素,或者当 n < 0 时从结尾删除 n 个元素</p>
|
||||
<p>创建一个切片,当n > 0时从开头删除n个元素,或者当n < 0时从结尾删除n个元素</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -1135,7 +1135,7 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Sort[T lancetconstraints.Ordered](slice []T, sortOrder ...string)
|
||||
func Sort[T constraints.Ordered](slice []T, sortOrder ...string)
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
@@ -1442,7 +1442,7 @@ func main() {
|
||||
|
||||
### <span id="Union">Union</span>
|
||||
|
||||
<p>合并多个切片.</p>
|
||||
<p>合并多个切片</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
|
||||
165
docs/strutil.md
165
docs/strutil.md
@@ -28,13 +28,16 @@ import (
|
||||
- [Capitalize](#Capitalize)
|
||||
- [IsString](#IsString)
|
||||
- [KebabCase](#KebabCase)
|
||||
- [UpperKebabCase](#UpperKebabCase)
|
||||
- [LowerFirst](#LowerFirst)
|
||||
- [UpperFirst](#UpperFirst)
|
||||
- [PadEnd](#PadEnd)
|
||||
- [PadStart](#PadStart)
|
||||
- [Reverse](#Reverse)
|
||||
- [SnakeCase](#SnakeCase)
|
||||
- [UpperSnakeCase](#UpperSnakeCase)
|
||||
- [SplitEx](#SplitEx)
|
||||
- [Substring](#Substring)
|
||||
- [Wrap](#Wrap)
|
||||
- [Unwrap](#Unwrap)
|
||||
|
||||
@@ -45,7 +48,7 @@ import (
|
||||
|
||||
|
||||
### <span id="After">After</span>
|
||||
<p>Creates substring in source string after position when char first appear.</p>
|
||||
<p>Returns the substring after the first occurrence of a specified string in the source string.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -75,7 +78,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="AfterLast">AfterLast</span>
|
||||
<p>Creates substring in source string after position when char last appear.</p>
|
||||
<p>Returns the substring after the last occurrence of a specified string in the source string.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -106,7 +109,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="Before">Before</span>
|
||||
<p>Creates substring in source string before position when char first appear.</p>
|
||||
<p>Returns the substring of the source string up to the first occurrence of the specified string.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -137,7 +140,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="BeforeLast">BeforeLast</span>
|
||||
<p>Creates substring in source string before position when char first appear.</p>
|
||||
<p>Returns the substring of the source string up to the last occurrence of the specified string.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -165,10 +168,8 @@ func main() {
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="CamelCase">CamelCase</span>
|
||||
<p>Covert string to camelCase string.</p>
|
||||
<p>Coverts string to camelCase string, non letters and numbers will be ignored.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -195,6 +196,75 @@ func main() {
|
||||
|
||||
s4 := strutil.CamelCase("foo bar")
|
||||
fmt.Println(s4) //fooBar
|
||||
|
||||
s4 := strutil.CamelCase("Foo-#1😄$_%^&*(1bar")
|
||||
fmt.Println(s4) //foo11Bar
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="KebabCase">KebabCase</span>
|
||||
<p>KebabCase covert string to kebab-case, non letters and numbers will be ignored.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func KebabCase(s string) string
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.KebabCase("Foo Bar-")
|
||||
fmt.Println(s1) //foo-bar
|
||||
|
||||
s2 := strutil.KebabCase("foo_Bar")
|
||||
fmt.Println(s2) //foo-bar
|
||||
|
||||
s3 := strutil.KebabCase("fooBar")
|
||||
fmt.Println(s3) //foo-bar
|
||||
|
||||
s4 := strutil.KebabCase("__FOO_BAR__")
|
||||
fmt.Println(s4) //foo-bar
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="UpperKebabCase">UpperKebabCase</span>
|
||||
<p>UpperKebabCase covert string to upper KEBAB-CASE, non letters and numbers will be ignored.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func KebabCase(s string) string
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.UpperKebabCase("Foo Bar-")
|
||||
fmt.Println(s1) //FOO-BAR
|
||||
|
||||
s2 := strutil.UpperKebabCase("foo_Bar")
|
||||
fmt.Println(s2) //FOO-BAR
|
||||
|
||||
s3 := strutil.UpperKebabCase("fooBar")
|
||||
fmt.Println(s3) //FOO-BAR
|
||||
|
||||
s4 := strutil.UpperKebabCase("__FOO_BAR__")
|
||||
fmt.Println(s4) //FOO-BAR
|
||||
}
|
||||
```
|
||||
|
||||
@@ -457,7 +527,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="SnakeCase">SnakeCase</span>
|
||||
<p>Covert string to snake_case.</p>
|
||||
<p>Coverts string to snake_case, non letters and numbers will be ignored.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -483,14 +553,47 @@ func main() {
|
||||
fmt.Println(s3) //foo_bar
|
||||
|
||||
s4 := strutil.SnakeCase("__FOO_BAR__")
|
||||
fmt.Println(s4) //f_o_o_b_a_r
|
||||
fmt.Println(s4) //foo_bar
|
||||
|
||||
s5 := strutil.SnakeCase("aBbc-s$@a&%_B.B^C")
|
||||
fmt.Println(s5) //a_bbc_s_a_b_b_c
|
||||
s5 := strutil.SnakeCase("Foo-#1😄$_%^&*(1bar")
|
||||
fmt.Println(s5) //foo_1_1_bar
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="UpperSnakeCase">UpperSnakeCase</span>
|
||||
<p>Coverts string to upper KEBAB-CASE, non letters and numbers will be ignored.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func SnakeCase(s string) string
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.UpperSnakeCase("Foo Bar-")
|
||||
fmt.Println(s1) //FOO_BAR
|
||||
|
||||
s2 := strutil.UpperSnakeCase("foo_Bar")
|
||||
fmt.Println(s2) //FOO_BAR
|
||||
|
||||
s3 := strutil.UpperSnakeCase("fooBar")
|
||||
fmt.Println(s3) //FOO_BAR
|
||||
|
||||
s4 := strutil.UpperSnakeCase("__FOO_BAR__")
|
||||
fmt.Println(s4) //FOO_BAR
|
||||
|
||||
s5 := strutil.UpperSnakeCase("Foo-#1😄$_%^&*(1bar")
|
||||
fmt.Println(s5) //FOO_1_1_BAR
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="SplitEx">SplitEx</span>
|
||||
@@ -529,9 +632,45 @@ func main() {
|
||||
|
||||
|
||||
|
||||
### <span id="Substring">Substring</span>
|
||||
<p>Returns a substring of the specified length starting at the specified offset position.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Substring(s string, offset int, length uint) string
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := strutil.Substring("abcde", 1, 3)
|
||||
fmt.Println(result1) //bcd
|
||||
|
||||
result2 := strutil.Substring("abcde", 1, 5)
|
||||
fmt.Println(result2) //bcde
|
||||
|
||||
result3 := strutil.Substring("abcde", -1, 3)
|
||||
fmt.Println(result3) //e
|
||||
|
||||
result4 := strutil.Substring("abcde", -2, 2)
|
||||
fmt.Println(result4) //de
|
||||
|
||||
result5 := strutil.Substring("abcde", -2, 3)
|
||||
fmt.Println(result5) //de
|
||||
|
||||
result6 := strutil.Substring("你好,欢迎你", 0, 2)
|
||||
fmt.Println(result6) //你好
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Wrap">Wrap</span>
|
||||
<p>Wrap a string with another string.</p>
|
||||
<p>Wrap a string with given string.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -568,7 +707,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="Wrap">Wrap</span>
|
||||
<p>Unwrap a given string from anther string. will change str value.</p>
|
||||
<p>Unwrap a given string from anther string. will change source string.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
|
||||
@@ -28,13 +28,16 @@ import (
|
||||
- [Capitalize](#Capitalize)
|
||||
- [IsString](#IsString)
|
||||
- [KebabCase](#KebabCase)
|
||||
- [UpperKebabCase](#UpperKebabCase)
|
||||
- [LowerFirst](#LowerFirst)
|
||||
- [UpperFirst](#UpperFirst)
|
||||
- [PadEnd](#PadEnd)
|
||||
- [PadStart](#PadStart)
|
||||
- [Reverse](#Reverse)
|
||||
- [SnakeCase](#SnakeCase)
|
||||
- [UpperSnakeCase](#UpperSnakeCase)
|
||||
- [SplitEx](#SplitEx)
|
||||
- [Substring](#Substring)
|
||||
- [Wrap](#Wrap)
|
||||
- [Unwrap](#Unwrap)
|
||||
|
||||
@@ -46,7 +49,7 @@ import (
|
||||
|
||||
|
||||
### <span id="After">After</span>
|
||||
<p>截取源字符串中char首次出现时的位置之后的子字符串</p>
|
||||
<p>返回源字符串中特定字符串首次出现时的位置之后的子字符串</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -76,7 +79,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="AfterLast">AfterLast</span>
|
||||
<p>截取源字符串中char最后一次出现时的位置之后的子字符串</p>
|
||||
<p>返回源字符串中指定字符串最后一次出现时的位置之后的子字符串</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -107,7 +110,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="Before">Before</span>
|
||||
<p>截取源字符串中char首次出现时的位置之前的子字符串</p>
|
||||
<p>返回源字符串中指定字符串第一次出现时的位置之前的子字符串</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -138,7 +141,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="BeforeLast">BeforeLast</span>
|
||||
<p>截取源字符串中char最后一次出现时的位置之前的子字符串</p>
|
||||
<p>返回源字符串中指定字符串最后一次出现时的位置之前的子字符串</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -169,7 +172,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="CamelCase">CamelCase</span>
|
||||
<p>将字符串转换为驼峰式字符串</p>
|
||||
<p>将字符串转换为驼峰式字符串, 非字母和数字会被忽略</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -196,6 +199,9 @@ func main() {
|
||||
|
||||
s4 := strutil.CamelCase("foo bar")
|
||||
fmt.Println(s4) //fooBar
|
||||
|
||||
s4 := strutil.CamelCase("Foo-#1😄$_%^&*(1bar")
|
||||
fmt.Println(s4) //foo11Bar
|
||||
}
|
||||
```
|
||||
|
||||
@@ -233,7 +239,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="IsString">IsString</span>
|
||||
<p>检查值的数据类型是否为字符串</p>
|
||||
<p>判断传入参数的数据类型是否为字符串</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -261,7 +267,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="KebabCase">KebabCase</span>
|
||||
<p>将字符串转换为kebab-case</p>
|
||||
<p>将字符串转换为kebab-case, 非字母和数字会被忽略</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -287,7 +293,40 @@ func main() {
|
||||
fmt.Println(s3) //foo-bar
|
||||
|
||||
s4 := strutil.KebabCase("__FOO_BAR__")
|
||||
fmt.Println(s4) //f-o-o-b-a-r
|
||||
fmt.Println(s4) //foo-bar
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="UpperKebabCase">UpperKebabCase</span>
|
||||
<p>将字符串转换为大写KEBAB-CASE, 非字母和数字会被忽略</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func KebabCase(s string) string
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.UpperKebabCase("Foo Bar-")
|
||||
fmt.Println(s1) //FOO-BAR
|
||||
|
||||
s2 := strutil.UpperKebabCase("foo_Bar")
|
||||
fmt.Println(s2) //FOO-BAR
|
||||
|
||||
s3 := strutil.UpperKebabCase("fooBar")
|
||||
fmt.Println(s3) //FOO-BAR
|
||||
|
||||
s4 := strutil.UpperKebabCase("__FOO_BAR__")
|
||||
fmt.Println(s4) //FOO-BAR
|
||||
}
|
||||
```
|
||||
|
||||
@@ -329,7 +368,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="UpperFirst">UpperFirst</span>
|
||||
<p>将字符串的第一个字符转换为大写</p>
|
||||
<p>将字符串的第一个字符转换为大写形式</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -458,7 +497,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="SnakeCase">SnakeCase</span>
|
||||
<p>将字符串转换为snake_case形式</p>
|
||||
<p>将字符串转换为snake_case形式, 非字母和数字会被忽略</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -484,10 +523,45 @@ func main() {
|
||||
fmt.Println(s3) //foo_bar
|
||||
|
||||
s4 := strutil.SnakeCase("__FOO_BAR__")
|
||||
fmt.Println(s4) //f_o_o_b_a_r
|
||||
fmt.Println(s4) //foo_bar
|
||||
|
||||
s5 := strutil.SnakeCase("aBbc-s$@a&%_B.B^C")
|
||||
fmt.Println(s5) //a_bbc_s_a_b_b_c
|
||||
s5 := strutil.SnakeCase("Foo-#1😄$_%^&*(1bar")
|
||||
fmt.Println(s5) //foo_1_1_bar
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="UpperSnakeCase">UpperSnakeCase</span>
|
||||
<p>将字符串转换为大写SNAKE_CASE形式, 非字母和数字会被忽略</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func SnakeCase(s string) string
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.UpperSnakeCase("Foo Bar-")
|
||||
fmt.Println(s1) //FOO_BAR
|
||||
|
||||
s2 := strutil.UpperSnakeCase("foo_Bar")
|
||||
fmt.Println(s2) //FOO_BAR
|
||||
|
||||
s3 := strutil.UpperSnakeCase("fooBar")
|
||||
fmt.Println(s3) //FOO_BAR
|
||||
|
||||
s4 := strutil.UpperSnakeCase("__FOO_BAR__")
|
||||
fmt.Println(s4) //FOO_BAR
|
||||
|
||||
s5 := strutil.UpperSnakeCase("Foo-#1😄$_%^&*(1bar")
|
||||
fmt.Println(s5) //FOO_1_1_BAR
|
||||
}
|
||||
```
|
||||
|
||||
@@ -527,6 +601,42 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Substring">Substring</span>
|
||||
<p>根据指定的位置和长度截取子字符串</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Substring(s string, offset int, length uint) string
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := strutil.Substring("abcde", 1, 3)
|
||||
fmt.Println(result1) //bcd
|
||||
|
||||
result2 := strutil.Substring("abcde", 1, 5)
|
||||
fmt.Println(result2) //bcde
|
||||
|
||||
result3 := strutil.Substring("abcde", -1, 3)
|
||||
fmt.Println(result3) //e
|
||||
|
||||
result4 := strutil.Substring("abcde", -2, 2)
|
||||
fmt.Println(result4) //de
|
||||
|
||||
result5 := strutil.Substring("abcde", -2, 3)
|
||||
fmt.Println(result5) //de
|
||||
|
||||
result6 := strutil.Substring("你好,欢迎你", 0, 2)
|
||||
fmt.Println(result6) //你好
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="Wrap">Wrap</span>
|
||||
|
||||
@@ -102,7 +102,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
isOsMac := system.IsMac
|
||||
isOsMac := system.IsMac()
|
||||
fmt.Println(isOsMac)
|
||||
}
|
||||
```
|
||||
@@ -211,7 +211,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="ExecCommand">CompareOsEnv</span>
|
||||
<p>Use shell /bin/bash -c(linux) or cmd (windows) to execute command.</p>
|
||||
<p>Execute shell command, return the stdout and stderr string of command, and error if error occur. param `command` is a complete command string, like, ls -a (linux), dir(windows), ping 127.0.0.1. In linux, use /bin/bash -c to execute command, In windows, use powershell.exe to execute command.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -227,10 +227,24 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
out, errout, err := system.ExecCommand("ls")
|
||||
fmt.Println(out)
|
||||
fmt.Println(errout)
|
||||
fmt.Println(err)
|
||||
// linux or mac
|
||||
stdout, stderr, err := system.ExecCommand("ls")
|
||||
fmt.Println("std out: ", stdout)
|
||||
fmt.Println("std err: ", stderr)
|
||||
assert.Equal("", stderr)
|
||||
|
||||
// windows
|
||||
stdout, stderr, err = system.ExecCommand("dir")
|
||||
fmt.Println("std out: ", stdout)
|
||||
fmt.Println("std err: ", stderr)
|
||||
|
||||
// error command
|
||||
stdout, stderr, err = system.ExecCommand("abc")
|
||||
fmt.Println("std out: ", stdout)
|
||||
fmt.Println("std err: ", stderr)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ import (
|
||||
- [GetOsEnv](#GetOsEnv)
|
||||
- [SetOsEnv](#SetOsEnv)
|
||||
- [RemoveOsEnv](#RemoveOsEnv)
|
||||
|
||||
- [CompareOsEnv](#CompareOsEnv)
|
||||
- [ExecCommand](#ExecCommand)
|
||||
- [GetOsBits](#GetOsBits)
|
||||
@@ -103,7 +102,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
isOsMac := system.IsMac
|
||||
isOsMac := system.IsMac()
|
||||
fmt.Println(isOsMac)
|
||||
}
|
||||
```
|
||||
@@ -212,7 +211,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="ExecCommand">ExecCommand</span>
|
||||
<p>使用shell /bin/bash -c(linux) 或 cmd (windows) 执行shell命令</p>
|
||||
<p>执行shell命令,返回命令的stdout和stderr字符串,如果出现错误,则返回错误。参数`command`是一个完整的命令字符串,如ls-a(linux),dir(windows),ping 127.0.0.1。在linux中,使用/bin/bash-c执行命令,在windows中,使用powershell.exe执行命令。</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -228,10 +227,24 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
out, errout, err := system.ExecCommand("ls")
|
||||
fmt.Println(out)
|
||||
fmt.Println(errout)
|
||||
fmt.Println(err)
|
||||
// linux or mac
|
||||
stdout, stderr, err := system.ExecCommand("ls")
|
||||
fmt.Println("std out: ", stdout)
|
||||
fmt.Println("std err: ", stderr)
|
||||
assert.Equal("", stderr)
|
||||
|
||||
// windows
|
||||
stdout, stderr, err = system.ExecCommand("dir")
|
||||
fmt.Println("std out: ", stdout)
|
||||
fmt.Println("std err: ", stderr)
|
||||
|
||||
// error command
|
||||
stdout, stderr, err = system.ExecCommand("abc")
|
||||
fmt.Println("std out: ", stdout)
|
||||
fmt.Println("std err: ", stderr)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ import (
|
||||
- [IsUrl](#IsUrl)
|
||||
- [IsWeakPassword](#IsWeakPassword)
|
||||
- [IsZeroValue](#IsZeroValue)
|
||||
- [IsGBK](#IsGBK)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
@@ -821,7 +822,34 @@ func main() {
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="IsGBK">IsGBK</span>
|
||||
<p>Checks if data encoding is gbk(Chinese character internal code extension specification). this function is implemented by whether double bytes fall within the encoding range of gbk,while each byte of utf-8 encoding format falls within the encoding range of gbk.Therefore, utf8.valid() should be called first to check whether it is not utf-8 encoding and then call IsGBK() to check gbk encoding. like the example.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func IsGBK(data []byte) bool
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/validator"
|
||||
)
|
||||
|
||||
func main() {
|
||||
data := []byte("你好")
|
||||
|
||||
// check utf8 first
|
||||
if utf8.Valid(data) {
|
||||
fmt.Println("data encoding is utf-8")
|
||||
}else if(validator.IsGBK(data)) {
|
||||
fmt.Println("data encoding is GBK")
|
||||
}
|
||||
fmt.Println("data encoding is unknown")
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ import (
|
||||
- [IsUrl](#IsUrl)
|
||||
- [IsWeakPassword](#IsWeakPassword)
|
||||
- [IsZeroValue](#IsZeroValue)
|
||||
- [IsGBK](#IsGBK)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
@@ -458,8 +459,6 @@ func main() {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="IsEmptyString">IsEmptyString</span>
|
||||
<p>验证字符串是否是空字符串</p>
|
||||
|
||||
@@ -487,7 +486,6 @@ func main() {
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="IsFloatStr">IsFloatStr</span>
|
||||
<p>验证字符串是否是可以转换为浮点数</p>
|
||||
|
||||
@@ -573,8 +571,6 @@ func main() {
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="IsRegexMatch">IsRegexMatch</span>
|
||||
<p>验证字符串是否可以匹配正则表达式</p>
|
||||
|
||||
@@ -600,7 +596,6 @@ func main() {
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="IsIntStr">IsIntStr</span>
|
||||
<p>验证字符串是否是可以转换为整数</p>
|
||||
|
||||
@@ -820,3 +815,31 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsGBK">IsGBK</span>
|
||||
<p>检查数据编码是否为gbk(汉字内部代码扩展规范)。该函数的实现取决于双字节是否在gbk的编码范围内,而utf-8编码格式的每个字节都在gbk编码范围内。因此,应该首先调用utf8.valid检查它是否是utf-8编码,然后调用IsGBK检查gbk编码。如示例所示。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func IsGBK(data []byte) bool
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/validator"
|
||||
)
|
||||
|
||||
func main() {
|
||||
data := []byte("你好")
|
||||
|
||||
// 先检查utf8编码
|
||||
if utf8.Valid(data) {
|
||||
fmt.Println("data encoding is utf-8")
|
||||
}else if(validator.IsGBK(data)) {
|
||||
fmt.Println("data encoding is GBK")
|
||||
}
|
||||
fmt.Println("data encoding is unknown")
|
||||
}
|
||||
```
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
@@ -19,7 +18,8 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// IsExist checks if a file or directory exists
|
||||
// IsExist checks if a file or directory exists.
|
||||
// Play: https://go.dev/play/p/nKKXt8ZQbmh
|
||||
func IsExist(path string) bool {
|
||||
_, err := os.Stat(path)
|
||||
if err == nil {
|
||||
@@ -31,7 +31,8 @@ func IsExist(path string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// CreateFile create a file in path
|
||||
// CreateFile create a file in path.
|
||||
// Play: https://go.dev/play/p/lDt8PEsTNKI
|
||||
func CreateFile(path string) bool {
|
||||
file, err := os.Create(path)
|
||||
if err != nil {
|
||||
@@ -42,12 +43,14 @@ func CreateFile(path string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// CreateDir create directory in absolute path. param `absPath` like /a/, /a/b/
|
||||
// CreateDir create directory in absolute path. param `absPath` like /a/, /a/b/.
|
||||
// Play: https://go.dev/play/p/qUuCe1OGQnM
|
||||
func CreateDir(absPath string) error {
|
||||
return os.MkdirAll(path.Dir(absPath), os.ModePerm)
|
||||
}
|
||||
|
||||
// IsDir checks if the path is directory or not
|
||||
// IsDir checks if the path is directory or not.
|
||||
// Play: https://go.dev/play/p/WkVwEKqtOWk
|
||||
func IsDir(path string) bool {
|
||||
file, err := os.Stat(path)
|
||||
if err != nil {
|
||||
@@ -56,12 +59,14 @@ func IsDir(path string) bool {
|
||||
return file.IsDir()
|
||||
}
|
||||
|
||||
// RemoveFile remove the path file
|
||||
// RemoveFile remove the path file.
|
||||
// Play: https://go.dev/play/p/P2y0XW8a1SH
|
||||
func RemoveFile(path string) error {
|
||||
return os.Remove(path)
|
||||
}
|
||||
|
||||
// CopyFile copy src file to dest file
|
||||
// CopyFile copy src file to dest file.
|
||||
// Play: https://go.dev/play/p/Jg9AMJMLrJi
|
||||
func CopyFile(srcFilePath string, dstFilePath string) error {
|
||||
srcFile, err := os.Open(srcFilePath)
|
||||
if err != nil {
|
||||
@@ -78,17 +83,21 @@ func CopyFile(srcFilePath string, dstFilePath string) error {
|
||||
var tmp = make([]byte, 1024*4)
|
||||
for {
|
||||
n, err := srcFile.Read(tmp)
|
||||
distFile.Write(tmp[:n])
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
_, err = distFile.Write(tmp[:n])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//ClearFile write empty string to path file
|
||||
// ClearFile write empty string to path file.
|
||||
// Play: https://go.dev/play/p/NRZ0ZT-G94H
|
||||
func ClearFile(path string) error {
|
||||
f, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||
if err != nil {
|
||||
@@ -100,16 +109,18 @@ func ClearFile(path string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
//ReadFileToString return string of file content
|
||||
// ReadFileToString return string of file content.
|
||||
// Play: https://go.dev/play/p/cmfwp_5SQTp
|
||||
func ReadFileToString(path string) (string, error) {
|
||||
bytes, err := ioutil.ReadFile(path)
|
||||
bytes, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(bytes), nil
|
||||
}
|
||||
|
||||
// ReadFileByLine read file line by line
|
||||
// ReadFileByLine read file line by line.
|
||||
// Play: https://go.dev/play/p/svJP_7ZrBrD
|
||||
func ReadFileByLine(path string) ([]string, error) {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
@@ -135,13 +146,14 @@ func ReadFileByLine(path string) ([]string, error) {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// ListFileNames return all file names in the path
|
||||
// ListFileNames return all file names in the path.
|
||||
// Play: https://go.dev/play/p/Tjd7Y07rejl
|
||||
func ListFileNames(path string) ([]string, error) {
|
||||
if !IsExist(path) {
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
fs, err := ioutil.ReadDir(path)
|
||||
fs, err := os.ReadDir(path)
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
@@ -161,7 +173,8 @@ func ListFileNames(path string) ([]string, error) {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Zip create zip file, fpath could be a single file or a directory
|
||||
// Zip create zip file, fpath could be a single file or a directory.
|
||||
// Play: https://go.dev/play/p/j-3sWBp8ik_P
|
||||
func Zip(fpath string, destPath string) error {
|
||||
zipFile, err := os.Create(destPath)
|
||||
if err != nil {
|
||||
@@ -172,7 +185,7 @@ func Zip(fpath string, destPath string) error {
|
||||
archive := zip.NewWriter(zipFile)
|
||||
defer archive.Close()
|
||||
|
||||
filepath.Walk(fpath, func(path string, info os.FileInfo, err error) error {
|
||||
err = filepath.Walk(fpath, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -209,10 +222,15 @@ func Zip(fpath string, destPath string) error {
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnZip unzip the file and save it to destPath
|
||||
// UnZip unzip the file and save it to destPath.
|
||||
// Play: https://go.dev/play/p/g0w34kS7B8m
|
||||
func UnZip(zipFile string, destPath string) error {
|
||||
|
||||
zipReader, err := zip.OpenReader(zipFile)
|
||||
@@ -229,9 +247,13 @@ func UnZip(zipFile string, destPath string) error {
|
||||
}
|
||||
|
||||
if f.FileInfo().IsDir() {
|
||||
os.MkdirAll(path, os.ModePerm)
|
||||
err = os.MkdirAll(path, os.ModePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err = os.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil {
|
||||
err = os.MkdirAll(filepath.Dir(path), os.ModePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -267,7 +289,8 @@ func safeFilepathJoin(path1, path2 string) (string, error) {
|
||||
return filepath.Join(path1, filepath.Join("/", relPath)), nil
|
||||
}
|
||||
|
||||
// IsLink checks if a file is symbol link or not
|
||||
// IsLink checks if a file is symbol link or not.
|
||||
// Play: https://go.dev/play/p/TL-b-Kzvf44
|
||||
func IsLink(path string) bool {
|
||||
fi, err := os.Lstat(path)
|
||||
if err != nil {
|
||||
@@ -276,7 +299,8 @@ func IsLink(path string) bool {
|
||||
return fi.Mode()&os.ModeSymlink != 0
|
||||
}
|
||||
|
||||
// FileMode return file's mode and permission
|
||||
// FileMode return file's mode and permission.
|
||||
// Play: https://go.dev/play/p/2l2hI42fA3p
|
||||
func FileMode(path string) (fs.FileMode, error) {
|
||||
fi, err := os.Lstat(path)
|
||||
if err != nil {
|
||||
@@ -286,7 +310,8 @@ func FileMode(path string) (fs.FileMode, error) {
|
||||
}
|
||||
|
||||
// MiMeType return file mime type
|
||||
// param `file` should be string(file path) or *os.File
|
||||
// param `file` should be string(file path) or *os.File.
|
||||
// Play: https://go.dev/play/p/bd5sevSUZNu
|
||||
func MiMeType(file any) string {
|
||||
var mediatype string
|
||||
|
||||
|
||||
225
fileutil/file_example_test.go
Normal file
225
fileutil/file_example_test.go
Normal file
@@ -0,0 +1,225 @@
|
||||
package fileutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func ExampleIsExist() {
|
||||
|
||||
result1 := IsExist("./")
|
||||
result2 := IsExist("./xxx.go")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleCreateFile() {
|
||||
fname := "./test.txt"
|
||||
|
||||
result1 := IsExist(fname)
|
||||
|
||||
CreateFile(fname)
|
||||
|
||||
result2 := IsExist(fname)
|
||||
|
||||
os.Remove(fname)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleCreateDir() {
|
||||
pwd, _ := os.Getwd()
|
||||
dirPath := pwd + "/test_xxx/"
|
||||
|
||||
result1 := IsExist(dirPath)
|
||||
|
||||
err := CreateDir(dirPath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
result2 := IsExist(dirPath)
|
||||
|
||||
os.Remove(dirPath)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleIsDir() {
|
||||
|
||||
result1 := IsDir("./")
|
||||
result2 := IsDir("./xxx.go")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleRemoveFile() {
|
||||
srcFile := "./text.txt"
|
||||
CreateFile(srcFile)
|
||||
|
||||
copyFile := "./text_copy.txt"
|
||||
err := CopyFile(srcFile, copyFile)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
file, err := os.Open(copyFile)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
result1 := IsExist(copyFile)
|
||||
result2 := file.Name()
|
||||
|
||||
os.Remove(srcFile)
|
||||
os.Remove(copyFile)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// ./text_copy.txt
|
||||
}
|
||||
|
||||
func ExampleReadFileToString() {
|
||||
fname := "./test.txt"
|
||||
CreateFile(fname)
|
||||
|
||||
f, _ := os.OpenFile(fname, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||
defer f.Close()
|
||||
|
||||
_, err := f.WriteString("hello world")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
content, _ := ReadFileToString(fname)
|
||||
|
||||
os.Remove(fname)
|
||||
|
||||
fmt.Println(content)
|
||||
|
||||
// Output:
|
||||
// hello world
|
||||
}
|
||||
|
||||
func ExampleClearFile() {
|
||||
fname := "./test.txt"
|
||||
CreateFile(fname)
|
||||
|
||||
f, _ := os.OpenFile(fname, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||
defer f.Close()
|
||||
|
||||
_, err := f.WriteString("hello world")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
content1, _ := ReadFileToString(fname)
|
||||
|
||||
err = ClearFile(fname)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
content2, _ := ReadFileToString(fname)
|
||||
|
||||
os.Remove(fname)
|
||||
|
||||
fmt.Println(content1)
|
||||
fmt.Println(content2)
|
||||
|
||||
// Output:
|
||||
// hello world
|
||||
//
|
||||
}
|
||||
|
||||
func ExampleReadFileByLine() {
|
||||
fname := "./test.txt"
|
||||
CreateFile(fname)
|
||||
|
||||
f, _ := os.OpenFile(fname, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||
defer f.Close()
|
||||
|
||||
_, err := f.WriteString("hello\nworld")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
content, _ := ReadFileByLine(fname)
|
||||
|
||||
os.Remove(fname)
|
||||
|
||||
fmt.Println(content)
|
||||
|
||||
// Output:
|
||||
// [hello world]
|
||||
}
|
||||
|
||||
func ExampleListFileNames() {
|
||||
fileList, _ := ListFileNames("./")
|
||||
fmt.Println(fileList)
|
||||
|
||||
// Output:
|
||||
// [file.go file_example_test.go file_test.go]
|
||||
}
|
||||
|
||||
func ExampleZip() {
|
||||
srcFile := "./test.txt"
|
||||
CreateFile(srcFile)
|
||||
|
||||
zipFile := "./test.zip"
|
||||
err := Zip(srcFile, zipFile)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
result := IsExist(zipFile)
|
||||
|
||||
os.Remove(srcFile)
|
||||
os.Remove(zipFile)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleUnZip() {
|
||||
fname := "./test.txt"
|
||||
file, _ := os.Create(fname)
|
||||
|
||||
_, err := file.WriteString("hello\nworld")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
f, _ := os.Open(fname)
|
||||
defer f.Close()
|
||||
|
||||
mimeType := MiMeType(f)
|
||||
fmt.Println(mimeType)
|
||||
|
||||
os.Remove(fname)
|
||||
|
||||
// Output:
|
||||
// application/octet-stream
|
||||
}
|
||||
@@ -25,9 +25,10 @@ func TestCreateFile(t *testing.T) {
|
||||
f := "./text.txt"
|
||||
if CreateFile(f) {
|
||||
file, err := os.Open(f)
|
||||
defer file.Close()
|
||||
assert.IsNil(err)
|
||||
assert.Equal(f, file.Name())
|
||||
|
||||
defer file.Close()
|
||||
} else {
|
||||
t.FailNow()
|
||||
}
|
||||
@@ -113,7 +114,11 @@ func TestReadFileToString(t *testing.T) {
|
||||
|
||||
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||
defer f.Close()
|
||||
f.WriteString("hello world")
|
||||
|
||||
_, err := f.WriteString("hello world")
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
}
|
||||
|
||||
content, _ := ReadFileToString(path)
|
||||
assert.Equal("hello world", content)
|
||||
@@ -130,9 +135,12 @@ func TestClearFile(t *testing.T) {
|
||||
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||
defer f.Close()
|
||||
|
||||
f.WriteString("hello world")
|
||||
_, err := f.WriteString("hello world")
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
}
|
||||
|
||||
err := ClearFile(path)
|
||||
err = ClearFile(path)
|
||||
assert.IsNil(err)
|
||||
|
||||
content, _ := ReadFileToString(path)
|
||||
@@ -148,8 +156,13 @@ func TestReadFileByLine(t *testing.T) {
|
||||
CreateFile(path)
|
||||
|
||||
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||
|
||||
defer f.Close()
|
||||
f.WriteString("hello\nworld")
|
||||
|
||||
_, err := f.WriteString("hello\nworld")
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
}
|
||||
|
||||
expected := []string{"hello", "world"}
|
||||
actual, _ := ReadFileByLine(path)
|
||||
@@ -166,10 +179,14 @@ func TestZipAndUnZip(t *testing.T) {
|
||||
|
||||
file, _ := os.OpenFile(srcFile, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||
defer file.Close()
|
||||
file.WriteString("hello\nworld")
|
||||
|
||||
_, err := file.WriteString("hello\nworld")
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
zipFile := "./text.zip"
|
||||
err := Zip(srcFile, zipFile)
|
||||
err = Zip(srcFile, zipFile)
|
||||
assert.IsNil(err)
|
||||
|
||||
unZipPath := "./unzip"
|
||||
|
||||
@@ -4,14 +4,68 @@
|
||||
// Package formatter implements some functions to format string, struct.
|
||||
package formatter
|
||||
|
||||
import "strings"
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/exp/constraints"
|
||||
)
|
||||
|
||||
// Comma add comma to a number value by every 3 numbers from right. ahead by symbol char.
|
||||
// if value is invalid number string eg "aa", return empty string
|
||||
// Comma("12345", "$") => "$12,345", Comma(12345, "$") => "$12,345"
|
||||
// Play: https://go.dev/play/p/eRD5k2vzUVX
|
||||
func Comma[T constraints.Float | constraints.Integer | string](value T, symbol string) string {
|
||||
s, err := numberToString(value)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Comma add comma to number by every 3 numbers from right. ahead by symbol char
|
||||
func Comma(v any, symbol string) string {
|
||||
s := numString(v)
|
||||
dotIndex := strings.Index(s, ".")
|
||||
if dotIndex != -1 {
|
||||
return symbol + commaString(s[:dotIndex]) + s[dotIndex:]
|
||||
}
|
||||
|
||||
return symbol + commaString(s)
|
||||
}
|
||||
|
||||
func commaString(s string) string {
|
||||
if len(s) <= 3 {
|
||||
return s
|
||||
}
|
||||
return commaString(s[:len(s)-3]) + "," + commaString(s[len(s)-3:])
|
||||
}
|
||||
|
||||
func numberToString(value any) (string, error) {
|
||||
switch reflect.TypeOf(value).Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return fmt.Sprintf("%v", value), nil
|
||||
|
||||
// todo: need to handle 12345678.9 => 1.23456789e+07
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return fmt.Sprintf("%v", value), nil
|
||||
|
||||
case reflect.String:
|
||||
{
|
||||
sv := fmt.Sprintf("%v", value)
|
||||
if strings.Contains(sv, ".") {
|
||||
_, err := strconv.ParseFloat(sv, 64)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return sv, nil
|
||||
} else {
|
||||
_, err := strconv.ParseInt(sv, 10, 64)
|
||||
if err != nil {
|
||||
return "", nil
|
||||
}
|
||||
return sv, nil
|
||||
}
|
||||
}
|
||||
default:
|
||||
return "", nil
|
||||
}
|
||||
}
|
||||
|
||||
18
formatter/formatter_example_test.go
Normal file
18
formatter/formatter_example_test.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package formatter
|
||||
|
||||
import "fmt"
|
||||
|
||||
func ExampleComma() {
|
||||
result1 := Comma("123", "")
|
||||
result2 := Comma("12345", "$")
|
||||
result3 := Comma(1234567, "¥")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 123
|
||||
// $12,345
|
||||
// ¥1,234,567
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package formatter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func commaString(s string) string {
|
||||
if len(s) <= 3 {
|
||||
return s
|
||||
}
|
||||
return commaString(s[:len(s)-3]) + "," + commaString(s[len(s)-3:])
|
||||
}
|
||||
|
||||
func numString(value any) string {
|
||||
switch reflect.TypeOf(value).Kind() {
|
||||
case reflect.Int, reflect.Int64, reflect.Float32, reflect.Float64:
|
||||
return fmt.Sprintf("%v", value)
|
||||
case reflect.String:
|
||||
{
|
||||
sv := fmt.Sprintf("%v", value)
|
||||
if strings.Contains(sv, ".") {
|
||||
_, err := strconv.ParseFloat(sv, 64)
|
||||
if err == nil {
|
||||
return sv
|
||||
}
|
||||
} else {
|
||||
_, err := strconv.ParseInt(sv, 10, 64)
|
||||
if err == nil {
|
||||
return sv
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -12,12 +12,16 @@ func TestComma(t *testing.T) {
|
||||
assert.Equal("", Comma("", ""))
|
||||
assert.Equal("", Comma("aa", ""))
|
||||
assert.Equal("", Comma("aa.a", ""))
|
||||
assert.Equal("", Comma([]int{1}, ""))
|
||||
assert.Equal("123", Comma("123", ""))
|
||||
assert.Equal("12,345", Comma("12345", ""))
|
||||
assert.Equal("12,345.6789", Comma("12345.6789", ""))
|
||||
assert.Equal("123,456,789,000", Comma("123456789000", ""))
|
||||
|
||||
assert.Equal("12,345", Comma(12345, ""))
|
||||
assert.Equal("$12,345", Comma(12345, "$"))
|
||||
assert.Equal("¥12,345", Comma(12345, "¥"))
|
||||
assert.Equal("12,345.6789", Comma(12345.6789, ""))
|
||||
assert.Equal("12,345.6789", Comma(+12345.6789, ""))
|
||||
// assert.Equal("12,345,678.9", Comma(12345678.9, ""))
|
||||
assert.Equal("123,456,789,000", Comma(123456789000, ""))
|
||||
}
|
||||
|
||||
@@ -5,11 +5,13 @@
|
||||
package function
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
// After creates a function that invokes func once it's called n or more times
|
||||
// After creates a function that invokes func once it's called n or more times.
|
||||
// Play: https://go.dev/play/p/8mQhkFmsgqs
|
||||
func After(n int, fn any) func(args ...any) []reflect.Value {
|
||||
// Catch programming error while constructing the closure
|
||||
mustBeFunction(fn)
|
||||
@@ -23,7 +25,8 @@ func After(n int, fn any) func(args ...any) []reflect.Value {
|
||||
}
|
||||
}
|
||||
|
||||
// Before creates a function that invokes func once it's called less than n times
|
||||
// Before creates a function that invokes func once it's called less than n times.
|
||||
// Play: https://go.dev/play/p/0HqUDIFZ3IL
|
||||
func Before(n int, fn any) func(args ...any) []reflect.Value {
|
||||
// Catch programming error while constructing the closure
|
||||
mustBeFunction(fn)
|
||||
@@ -40,41 +43,48 @@ func Before(n int, fn any) func(args ...any) []reflect.Value {
|
||||
}
|
||||
}
|
||||
|
||||
// Fn is for curry function which is func(...any) any
|
||||
type Fn func(...any) any
|
||||
// CurryFn is for make curry function
|
||||
type CurryFn[T any] func(...T) T
|
||||
|
||||
// Curry make a curry function
|
||||
func (f Fn) Curry(i any) func(...any) any {
|
||||
return func(values ...any) any {
|
||||
v := append([]any{i}, values...)
|
||||
return f(v...)
|
||||
// New make a curry function for specific value.
|
||||
// Play: Todo
|
||||
func (cf CurryFn[T]) New(val T) func(...T) T {
|
||||
return func(vals ...T) T {
|
||||
args := append([]T{val}, vals...)
|
||||
return cf(args...)
|
||||
}
|
||||
}
|
||||
|
||||
// Compose compose the functions from right to left
|
||||
func Compose(fnList ...func(...any) any) func(...any) any {
|
||||
return func(s ...any) any {
|
||||
f := fnList[0]
|
||||
restFn := fnList[1:]
|
||||
// Compose compose the functions from right to left.
|
||||
// Play: Todo
|
||||
func Compose[T any](fnList ...func(...T) T) func(...T) T {
|
||||
return func(args ...T) T {
|
||||
firstFn := fnList[0]
|
||||
restFns := fnList[1:]
|
||||
|
||||
if len(fnList) == 1 {
|
||||
return f(s...)
|
||||
return firstFn(args...)
|
||||
}
|
||||
|
||||
return f(Compose(restFn...)(s...))
|
||||
fn := Compose(restFns...)
|
||||
arg := fn(args...)
|
||||
|
||||
return firstFn(arg)
|
||||
}
|
||||
}
|
||||
|
||||
// Delay make the function execution after delayed time
|
||||
// Delay make the function execution after delayed time.
|
||||
// Play: https://go.dev/play/p/Ivtc2ZE-Tye
|
||||
func Delay(delay time.Duration, fn any, args ...any) {
|
||||
// Catch programming error while constructing the closure
|
||||
mustBeFunction(fn)
|
||||
|
||||
time.Sleep(delay)
|
||||
invokeFunc(fn, args...)
|
||||
unsafeInvokeFunc(fn, args...)
|
||||
}
|
||||
|
||||
// Debounced creates a debounced function that delays invoking fn until after wait duration have elapsed since the last time the debounced function was invoked.
|
||||
// Play: https://go.dev/play/p/absuEGB_GN7
|
||||
func Debounced(fn func(), duration time.Duration) func() {
|
||||
// Catch programming error while constructing the closure
|
||||
mustBeFunction(fn)
|
||||
@@ -84,17 +94,16 @@ func Debounced(fn func(), duration time.Duration) func() {
|
||||
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-timer.C:
|
||||
go fn()
|
||||
}
|
||||
<-timer.C
|
||||
go fn()
|
||||
}
|
||||
}()
|
||||
|
||||
return func() { timer.Reset(duration) }
|
||||
}
|
||||
|
||||
// Schedule invoke function every duration time, util close the returned bool chan
|
||||
// Schedule invoke function every duration time, util close the returned bool channel.
|
||||
// Play: https://go.dev/play/p/hbON-Xeyn5N
|
||||
func Schedule(d time.Duration, fn any, args ...any) chan bool {
|
||||
// Catch programming error while constructing the closure
|
||||
mustBeFunction(fn)
|
||||
@@ -116,6 +125,7 @@ func Schedule(d time.Duration, fn any, args ...any) chan bool {
|
||||
|
||||
// Pipeline takes a list of functions and returns a function whose param will be passed into
|
||||
// the functions one by one.
|
||||
// Play: https://go.dev/play/p/mPdUVvj6HD6
|
||||
func Pipeline[T any](funcs ...func(T) T) func(T) T {
|
||||
return func(arg T) (result T) {
|
||||
result = arg
|
||||
@@ -125,3 +135,27 @@ func Pipeline[T any](funcs ...func(T) T) func(T) T {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func unsafeInvokeFunc(fn any, args ...any) []reflect.Value {
|
||||
fv := reflect.ValueOf(fn)
|
||||
params := make([]reflect.Value, len(args))
|
||||
for i, item := range args {
|
||||
params[i] = reflect.ValueOf(item)
|
||||
}
|
||||
return fv.Call(params)
|
||||
}
|
||||
|
||||
func functionValue(function any) reflect.Value {
|
||||
v := reflect.ValueOf(function)
|
||||
if v.Kind() != reflect.Func {
|
||||
panic(fmt.Sprintf("Invalid function type, value of type %T", function))
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func mustBeFunction(function any) {
|
||||
v := reflect.ValueOf(function)
|
||||
if v.Kind() != reflect.Func {
|
||||
panic(fmt.Sprintf("Invalid function type, value of type %T", function))
|
||||
}
|
||||
}
|
||||
|
||||
147
function/function_example_test.go
Normal file
147
function/function_example_test.go
Normal file
@@ -0,0 +1,147 @@
|
||||
package function
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func ExampleAfter() {
|
||||
fn := After(2, func() {
|
||||
fmt.Println("test")
|
||||
})
|
||||
|
||||
fn()
|
||||
fn()
|
||||
|
||||
// Output:
|
||||
// test
|
||||
}
|
||||
|
||||
func ExampleBefore() {
|
||||
fn := Before(2, func() {
|
||||
fmt.Println("test")
|
||||
})
|
||||
|
||||
fn()
|
||||
fn()
|
||||
fn()
|
||||
fn()
|
||||
|
||||
// Output:
|
||||
// test
|
||||
// test
|
||||
}
|
||||
|
||||
func ExampleCurryFn_New() {
|
||||
add := func(a, b int) int {
|
||||
return a + b
|
||||
}
|
||||
|
||||
var addCurry CurryFn[int] = func(values ...int) int {
|
||||
return add(values[0], values[1])
|
||||
}
|
||||
add1 := addCurry.New(1)
|
||||
|
||||
result := add1(2)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
}
|
||||
|
||||
func ExampleCompose() {
|
||||
toUpper := func(strs ...string) string {
|
||||
return strings.ToUpper(strs[0])
|
||||
}
|
||||
toLower := func(strs ...string) string {
|
||||
return strings.ToLower(strs[0])
|
||||
}
|
||||
transform := Compose(toUpper, toLower)
|
||||
|
||||
result := transform("aBCde")
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// ABCDE
|
||||
}
|
||||
|
||||
func ExampleDelay() {
|
||||
var print = func(s string) {
|
||||
fmt.Println(s)
|
||||
}
|
||||
|
||||
Delay(2*time.Second, print, "hello")
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
|
||||
func ExampleDebounced() {
|
||||
count := 0
|
||||
add := func() {
|
||||
count++
|
||||
}
|
||||
|
||||
debouncedAdd := Debounced(add, 50*time.Microsecond)
|
||||
|
||||
debouncedAdd()
|
||||
debouncedAdd()
|
||||
debouncedAdd()
|
||||
debouncedAdd()
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
fmt.Println(count)
|
||||
|
||||
debouncedAdd()
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
fmt.Println(count)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
}
|
||||
|
||||
func ExampleSchedule() {
|
||||
var result []string
|
||||
|
||||
appendFn := func(s string) {
|
||||
result = append(result, s)
|
||||
}
|
||||
|
||||
stop := Schedule(1*time.Second, appendFn, "*")
|
||||
|
||||
time.Sleep(3 * time.Second)
|
||||
close(stop)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [* * *]
|
||||
}
|
||||
|
||||
func ExamplePipeline() {
|
||||
addOne := func(x int) int {
|
||||
return x + 1
|
||||
}
|
||||
double := func(x int) int {
|
||||
return 2 * x
|
||||
}
|
||||
square := func(x int) int {
|
||||
return x * x
|
||||
}
|
||||
|
||||
fn := Pipeline(addOne, double, square)
|
||||
|
||||
result := fn(2)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 36
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package function
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func invokeFunc(fn any, args ...any) []reflect.Value {
|
||||
fv := functionValue(fn)
|
||||
params := make([]reflect.Value, len(args))
|
||||
for i, item := range args {
|
||||
params[i] = reflect.ValueOf(item)
|
||||
}
|
||||
return fv.Call(params)
|
||||
}
|
||||
|
||||
func unsafeInvokeFunc(fn any, args ...any) []reflect.Value {
|
||||
fv := reflect.ValueOf(fn)
|
||||
params := make([]reflect.Value, len(args))
|
||||
for i, item := range args {
|
||||
params[i] = reflect.ValueOf(item)
|
||||
}
|
||||
return fv.Call(params)
|
||||
}
|
||||
|
||||
func functionValue(function any) reflect.Value {
|
||||
v := reflect.ValueOf(function)
|
||||
if v.Kind() != reflect.Func {
|
||||
panic(fmt.Sprintf("Invalid function type, value of type %T", function))
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func mustBeFunction(function any) {
|
||||
v := reflect.ValueOf(function)
|
||||
if v.Kind() != reflect.Func {
|
||||
panic(fmt.Sprintf("Invalid function type, value of type %T", function))
|
||||
}
|
||||
}
|
||||
@@ -62,24 +62,26 @@ func TestCurry(t *testing.T) {
|
||||
add := func(a, b int) int {
|
||||
return a + b
|
||||
}
|
||||
var addCurry Fn = func(values ...any) any {
|
||||
return add(values[0].(int), values[1].(int))
|
||||
var addCurry CurryFn[int] = func(values ...int) int {
|
||||
return add(values[0], values[1])
|
||||
}
|
||||
add1 := addCurry.Curry(1)
|
||||
add1 := addCurry.New(1)
|
||||
|
||||
assert.Equal(3, add1(2))
|
||||
}
|
||||
|
||||
func TestCompose(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestCompose")
|
||||
|
||||
toUpper := func(a ...any) any {
|
||||
return strings.ToUpper(a[0].(string))
|
||||
toUpper := func(strs ...string) string {
|
||||
return strings.ToUpper(strs[0])
|
||||
}
|
||||
toLower := func(a ...any) any {
|
||||
return strings.ToLower(a[0].(string))
|
||||
toLower := func(strs ...string) string {
|
||||
return strings.ToLower(strs[0])
|
||||
}
|
||||
|
||||
expected := toUpper(toLower("aBCde"))
|
||||
|
||||
cf := Compose(toUpper, toLower)
|
||||
res := cf("aBCde")
|
||||
|
||||
|
||||
@@ -3,12 +3,18 @@ package function
|
||||
import "time"
|
||||
|
||||
// Watcher is used for record code excution time
|
||||
// Play: Todo
|
||||
type Watcher struct {
|
||||
startTime int64
|
||||
stopTime int64
|
||||
excuting bool
|
||||
}
|
||||
|
||||
// Start the watch timer.
|
||||
func NewWatcher() *Watcher {
|
||||
return &Watcher{}
|
||||
}
|
||||
|
||||
// Start the watch timer.
|
||||
func (w *Watcher) Start() {
|
||||
w.startTime = time.Now().UnixNano()
|
||||
|
||||
22
function/watcher_example_test.go
Normal file
22
function/watcher_example_test.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package function
|
||||
|
||||
import "fmt"
|
||||
|
||||
func ExampleWatcher() {
|
||||
w := NewWatcher()
|
||||
|
||||
w.Start()
|
||||
|
||||
longRunningTask()
|
||||
|
||||
w.Stop()
|
||||
|
||||
// eapsedTime := w.GetElapsedTime().Milliseconds()
|
||||
|
||||
fmt.Println("foo")
|
||||
|
||||
w.Reset()
|
||||
|
||||
// Output:
|
||||
// foo
|
||||
}
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
func TestWatcher(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestWatcher")
|
||||
|
||||
w := &Watcher{}
|
||||
w := NewWatcher()
|
||||
w.Start()
|
||||
|
||||
longRunningTask()
|
||||
|
||||
5
go.mod
5
go.mod
@@ -1,3 +1,8 @@
|
||||
module github.com/duke-git/lancet/v2
|
||||
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
golang.org/x/exp v0.0.0-20221208152030-732eee02a75a
|
||||
golang.org/x/text v0.5.0
|
||||
)
|
||||
|
||||
4
go.sum
Normal file
4
go.sum
Normal file
@@ -0,0 +1,4 @@
|
||||
golang.org/x/exp v0.0.0-20221208152030-732eee02a75a h1:4iLhBPcpqFmylhnkbY3W0ONLUYYkDAW9xMFLfxgsvCw=
|
||||
golang.org/x/exp v0.0.0-20221208152030-732eee02a75a/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
|
||||
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
@@ -3,14 +3,18 @@
|
||||
|
||||
// Package iterator provides a way to iterate over values stored in containers.
|
||||
// note:
|
||||
// 1. Full feature iterator is complicated, this pacakge is just a experiment to explore how iterators could work in Go.
|
||||
// 1. Full feature iterator is complicated, this package is just a experiment to explore how iterators could work in Go.
|
||||
// 2. The functionality of this package is very simple and limited, may not meet the actual dev needs.
|
||||
// 3. It is currently under development, unstable, and will not be completed for some time in the future.
|
||||
// So, based on above factors, you may not use it in production. but, anyone is welcome to improve it.
|
||||
// Hope that Go can support iterator in future. see https://github.com/golang/go/discussions/54245 and https://github.com/golang/go/discussions/56413
|
||||
package iterator
|
||||
|
||||
import "github.com/duke-git/lancet/v2/lancetconstraints"
|
||||
import (
|
||||
"context"
|
||||
|
||||
"golang.org/x/exp/constraints"
|
||||
)
|
||||
|
||||
// Iterator supports iterating over a sequence of values of type `E`.
|
||||
type Iterator[T any] interface {
|
||||
@@ -100,21 +104,15 @@ func (iter *sliceIterator[T]) HasNext() bool {
|
||||
|
||||
func (iter *sliceIterator[T]) Next() (T, bool) {
|
||||
iter.index++
|
||||
|
||||
ok := iter.index >= 0 && iter.index < len(iter.slice)
|
||||
|
||||
var item T
|
||||
if ok {
|
||||
item = iter.slice[iter.index]
|
||||
}
|
||||
return item, ok
|
||||
|
||||
// if len(iter.slice) == 0 {
|
||||
// var zero T
|
||||
// return zero, false
|
||||
// }
|
||||
// iter.index++
|
||||
// item := iter.slice[0]
|
||||
// iter.slice = iter.slice[1:]
|
||||
// return item, true
|
||||
return item, ok
|
||||
}
|
||||
|
||||
// Prev implements PrevIterator.
|
||||
@@ -142,7 +140,7 @@ func (iter *sliceIterator[T]) Set(value T) {
|
||||
|
||||
// FromRange creates a iterator which returns the numeric range between start inclusive and end
|
||||
// exclusive by the step size. start should be less than end, step shoud be positive.
|
||||
func FromRange[T lancetconstraints.Number](start, end, step T) Iterator[T] {
|
||||
func FromRange[T constraints.Integer | constraints.Float](start, end, step T) Iterator[T] {
|
||||
if end < start {
|
||||
panic("RangeIterator: start should be before end")
|
||||
} else if step <= 0 {
|
||||
@@ -152,15 +150,12 @@ func FromRange[T lancetconstraints.Number](start, end, step T) Iterator[T] {
|
||||
return &rangeIterator[T]{start: start, end: end, step: step}
|
||||
}
|
||||
|
||||
type rangeIterator[T lancetconstraints.Number] struct {
|
||||
type rangeIterator[T constraints.Integer | constraints.Float] struct {
|
||||
start, end, step T
|
||||
}
|
||||
|
||||
func (iter *rangeIterator[T]) HasNext() bool {
|
||||
if iter.start >= iter.end {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
return iter.start < iter.end
|
||||
}
|
||||
|
||||
func (iter *rangeIterator[T]) Next() (T, bool) {
|
||||
@@ -172,3 +167,41 @@ func (iter *rangeIterator[T]) Next() (T, bool) {
|
||||
iter.start += iter.step
|
||||
return num, true
|
||||
}
|
||||
|
||||
// FromRange creates a iterator which returns the numeric range between start inclusive and end
|
||||
// exclusive by the step size. start should be less than end, step shoud be positive.
|
||||
func FromChannel[T any](channel <-chan T) Iterator[T] {
|
||||
return &channelIterator[T]{channel: channel}
|
||||
}
|
||||
|
||||
type channelIterator[T any] struct {
|
||||
channel <-chan T
|
||||
}
|
||||
|
||||
func (iter *channelIterator[T]) Next() (T, bool) {
|
||||
item, ok := <-iter.channel
|
||||
return item, ok
|
||||
}
|
||||
|
||||
func (iter *channelIterator[T]) HasNext() bool {
|
||||
return len(iter.channel) == 0
|
||||
}
|
||||
|
||||
// ToChannel create a new goroutine to pull items from the channel iterator to the returned channel.
|
||||
func ToChannel[T any](ctx context.Context, iter Iterator[T], buffer int) <-chan T {
|
||||
result := make(chan T, buffer)
|
||||
|
||||
go func() {
|
||||
defer close(result)
|
||||
|
||||
for item, ok := iter.Next(); ok; item, ok = iter.Next() {
|
||||
select {
|
||||
case result <- item:
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
package iterator
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
@@ -47,4 +48,56 @@ func TestSliceIterator(t *testing.T) {
|
||||
assert.Equal(false, ok)
|
||||
})
|
||||
|
||||
t.Run("slice iterator ToSlice: ", func(t *testing.T) {
|
||||
iter := FromSlice([]int{1, 2, 3, 4})
|
||||
item, _ := iter.Next()
|
||||
assert.Equal(1, item)
|
||||
|
||||
data := ToSlice(iter)
|
||||
assert.Equal([]int{2, 3, 4}, data)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestRangeIterator(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestRangeIterator")
|
||||
|
||||
t.Run("range iterator: ", func(t *testing.T) {
|
||||
iter := FromRange(1, 4, 1)
|
||||
|
||||
item, ok := iter.Next()
|
||||
assert.Equal(1, item)
|
||||
assert.Equal(true, ok)
|
||||
|
||||
item, ok = iter.Next()
|
||||
assert.Equal(2, item)
|
||||
assert.Equal(true, ok)
|
||||
|
||||
item, ok = iter.Next()
|
||||
assert.Equal(3, item)
|
||||
assert.Equal(true, ok)
|
||||
|
||||
_, ok = iter.Next()
|
||||
assert.Equal(false, ok)
|
||||
assert.Equal(false, iter.HasNext())
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestChannelIterator(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestRangeIterator")
|
||||
|
||||
iter := FromSlice([]int{1, 2, 3, 4})
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
iter = FromChannel(ToChannel(ctx, iter, 0))
|
||||
item, ok := iter.Next()
|
||||
assert.Equal(1, item)
|
||||
assert.Equal(true, ok)
|
||||
assert.Equal(true, iter.HasNext())
|
||||
|
||||
cancel()
|
||||
|
||||
_, ok = iter.Next()
|
||||
assert.Equal(false, ok)
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
// Package iterator provides a way to iterate over values stored in containers.
|
||||
// note:
|
||||
// 1. Full feature iterator is complicated, this pacakge is just a experiment to explore how iterators could work in Go.
|
||||
// 1. Full feature iterator is complicated, this package is just a experiment to explore how iterators could work in Go.
|
||||
// 2. The functionality of this package is very simple and limited, may not meet the actual dev needs.
|
||||
// 3. It is currently under development, unstable, and will not be completed for some time in the future.
|
||||
// So, based on above factors, you may not use it in production. but, anyone is welcome to improve it.
|
||||
@@ -59,3 +59,81 @@ func (fr *filterIterator[T]) Next() (T, bool) {
|
||||
func (fr *filterIterator[T]) HasNext() bool {
|
||||
return fr.iter.HasNext()
|
||||
}
|
||||
|
||||
// Join creates an iterator that join all elements of iters[0], then all elements of iters[1] and so on.
|
||||
func Join[T any](iters ...Iterator[T]) Iterator[T] {
|
||||
return &joinIterator[T]{
|
||||
iters: iters,
|
||||
}
|
||||
}
|
||||
|
||||
type joinIterator[T any] struct {
|
||||
iters []Iterator[T]
|
||||
}
|
||||
|
||||
func (iter *joinIterator[T]) Next() (T, bool) {
|
||||
for len(iter.iters) > 0 {
|
||||
item, ok := iter.iters[0].Next()
|
||||
if ok {
|
||||
return item, true
|
||||
}
|
||||
iter.iters = iter.iters[1:]
|
||||
}
|
||||
var zero T
|
||||
return zero, false
|
||||
}
|
||||
|
||||
func (iter *joinIterator[T]) HasNext() bool {
|
||||
if len(iter.iters) == 0 {
|
||||
return false
|
||||
}
|
||||
if len(iter.iters) == 1 {
|
||||
return iter.iters[0].HasNext()
|
||||
}
|
||||
|
||||
result := iter.iters[0].HasNext()
|
||||
|
||||
for i := 1; i < len(iter.iters); i++ {
|
||||
it := iter.iters[i]
|
||||
hasNext := it.HasNext()
|
||||
result = result || hasNext
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Reduce reduces iter to a single value using the reduction function reducer
|
||||
func Reduce[T any, U any](iter Iterator[T], initial U, reducer func(U, T) U) U {
|
||||
acc := initial
|
||||
|
||||
for item, ok := iter.Next(); ok; item, ok = iter.Next() {
|
||||
acc = reducer(acc, item)
|
||||
}
|
||||
|
||||
return acc
|
||||
}
|
||||
|
||||
func Take[T any](it Iterator[T], num int) Iterator[T] {
|
||||
return &takeIterator[T]{it: it, num: num}
|
||||
}
|
||||
|
||||
type takeIterator[T any] struct {
|
||||
it Iterator[T]
|
||||
num int
|
||||
}
|
||||
|
||||
func (iter *takeIterator[T]) Next() (T, bool) {
|
||||
if iter.num <= 0 {
|
||||
var zero T
|
||||
return zero, false
|
||||
}
|
||||
item, ok := iter.it.Next()
|
||||
if ok {
|
||||
iter.num--
|
||||
}
|
||||
return item, ok
|
||||
}
|
||||
|
||||
func (iter *takeIterator[T]) HasNext() bool {
|
||||
return iter.num > 0
|
||||
}
|
||||
|
||||
73
iterator/operation_test.go
Normal file
73
iterator/operation_test.go
Normal file
@@ -0,0 +1,73 @@
|
||||
// Copyright 2022 dudaodong@gmail.com. All rights resulterved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package iterator provides a way to iterate over values stored in containers.
|
||||
// note:
|
||||
// 1. Full feature iterator is complicated, this package is just a experiment to explore how iterators could work in Go.
|
||||
// 2. The functionality of this package is very simple and limited, may not meet the actual dev needs.
|
||||
// 3. It is currently under development, unstable, and will not be completed for some time in the future.
|
||||
// So, based on above factors, you may not use it in production. but, anyone is welcome to improve it.
|
||||
// Hope that Go can support iterator in future. see https://github.com/golang/go/discussions/54245 and https://github.com/golang/go/discussions/56413
|
||||
package iterator
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestMapIterator(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestMapIterator")
|
||||
|
||||
iter := FromSlice([]int{1, 2, 3, 4})
|
||||
|
||||
iter = Map(iter, func(n int) int { return n / 2 })
|
||||
|
||||
result := ToSlice(iter)
|
||||
assert.Equal([]int{0, 1, 1, 2}, result)
|
||||
}
|
||||
|
||||
func TestFilterIterator(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestFilterIterator")
|
||||
|
||||
iter := FromSlice([]int{1, 2, 3, 4})
|
||||
|
||||
iter = Filter(iter, func(n int) bool { return n < 3 })
|
||||
|
||||
result := ToSlice(iter)
|
||||
assert.Equal([]int{1, 2}, result)
|
||||
}
|
||||
|
||||
func TestJoinIterator(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestJoinIterator")
|
||||
|
||||
iter1 := FromSlice([]int{1, 2})
|
||||
iter2 := FromSlice([]int{3, 4})
|
||||
|
||||
iter := Join(iter1, iter2)
|
||||
|
||||
item, ok := iter.Next()
|
||||
assert.Equal(1, item)
|
||||
assert.Equal(true, ok)
|
||||
|
||||
assert.Equal([]int{2, 3, 4}, ToSlice(iter))
|
||||
}
|
||||
|
||||
func TestReduce(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestReduce")
|
||||
|
||||
iter := FromSlice([]int{1, 2, 3, 4})
|
||||
sum := Reduce(iter, 0, func(a, b int) int { return a + b })
|
||||
assert.Equal(10, sum)
|
||||
}
|
||||
|
||||
func TestTakeIterator(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestTakeIterator")
|
||||
|
||||
iter := FromSlice([]int{1, 2, 3, 4, 5})
|
||||
|
||||
iter = Take(iter, 3)
|
||||
|
||||
result := ToSlice(iter)
|
||||
assert.Equal([]int{1, 2, 3}, result)
|
||||
}
|
||||
@@ -11,13 +11,3 @@ type Comparator interface {
|
||||
// Descending order: should return 1 -> v1 < v2, 0 -> v1 = v2, -1 -> v1 > v2
|
||||
Compare(v1, v2 any) int
|
||||
}
|
||||
|
||||
// Number contains all types of number and uintptr, used for generics constraint
|
||||
type Number interface {
|
||||
~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | ~float32 | ~float64
|
||||
}
|
||||
|
||||
// Ordered is a constraint that permits any ordered type: any type that supports the operators < <= >= >
|
||||
type Ordered interface {
|
||||
Number | ~string
|
||||
}
|
||||
|
||||
@@ -6,7 +6,8 @@ package maputil
|
||||
|
||||
import "reflect"
|
||||
|
||||
// Keys returns a slice of the map's keys
|
||||
// Keys returns a slice of the map's keys.
|
||||
// Play: https://go.dev/play/p/xNB5bTb97Wd
|
||||
func Keys[K comparable, V any](m map[K]V) []K {
|
||||
keys := make([]K, len(m))
|
||||
|
||||
@@ -19,7 +20,8 @@ func Keys[K comparable, V any](m map[K]V) []K {
|
||||
return keys
|
||||
}
|
||||
|
||||
// Values returns a slice of the map's values
|
||||
// Values returns a slice of the map's values.
|
||||
// Play: https://go.dev/play/p/CBKdUc5FTW6
|
||||
func Values[K comparable, V any](m map[K]V) []V {
|
||||
values := make([]V, len(m))
|
||||
|
||||
@@ -32,7 +34,8 @@ func Values[K comparable, V any](m map[K]V) []V {
|
||||
return values
|
||||
}
|
||||
|
||||
// Merge maps, next key will overwrite previous key
|
||||
// Merge maps, next key will overwrite previous key.
|
||||
// Play: https://go.dev/play/p/H95LENF1uB-
|
||||
func Merge[K comparable, V any](maps ...map[K]V) map[K]V {
|
||||
result := make(map[K]V, 0)
|
||||
|
||||
@@ -45,14 +48,16 @@ func Merge[K comparable, V any](maps ...map[K]V) map[K]V {
|
||||
return result
|
||||
}
|
||||
|
||||
// ForEach executes iteratee funcation for every key and value pair in map
|
||||
// ForEach executes iteratee funcation for every key and value pair in map.
|
||||
// Play: https://go.dev/play/p/OaThj6iNVXK
|
||||
func ForEach[K comparable, V any](m map[K]V, iteratee func(key K, value V)) {
|
||||
for k, v := range m {
|
||||
iteratee(k, v)
|
||||
}
|
||||
}
|
||||
|
||||
// Filter iterates over map, return a new map contains all key and value pairs pass the predicate function
|
||||
// Filter iterates over map, return a new map contains all key and value pairs pass the predicate function.
|
||||
// Play: https://go.dev/play/p/fSvF3wxuNG7
|
||||
func Filter[K comparable, V any](m map[K]V, predicate func(key K, value V) bool) map[K]V {
|
||||
result := make(map[K]V)
|
||||
|
||||
@@ -64,7 +69,8 @@ func Filter[K comparable, V any](m map[K]V, predicate func(key K, value V) bool)
|
||||
return result
|
||||
}
|
||||
|
||||
// Intersect iterates over maps, return a new map of key and value pairs in all given maps
|
||||
// Intersect iterates over maps, return a new map of key and value pairs in all given maps.
|
||||
// Play: https://go.dev/play/p/Zld0oj3sjcC
|
||||
func Intersect[K comparable, V any](maps ...map[K]V) map[K]V {
|
||||
if len(maps) == 0 {
|
||||
return map[K]V{}
|
||||
@@ -85,7 +91,7 @@ func Intersect[K comparable, V any](maps ...map[K]V) map[K]V {
|
||||
return m
|
||||
}
|
||||
|
||||
reduceMaps := make([]map[K]V, 2, 2)
|
||||
reduceMaps := make([]map[K]V, 2)
|
||||
result = reducer(maps[0], maps[1])
|
||||
|
||||
for i := 2; i < len(maps); i++ {
|
||||
@@ -97,7 +103,8 @@ func Intersect[K comparable, V any](maps ...map[K]V) map[K]V {
|
||||
return result
|
||||
}
|
||||
|
||||
// Minus creates an map of whose key in mapA but not in mapB
|
||||
// Minus creates a map of whose key in mapA but not in mapB.
|
||||
// Play: https://go.dev/play/p/3u5U9K7YZ9m
|
||||
func Minus[K comparable, V any](mapA, mapB map[K]V) map[K]V {
|
||||
result := make(map[K]V)
|
||||
|
||||
@@ -109,7 +116,8 @@ func Minus[K comparable, V any](mapA, mapB map[K]V) map[K]V {
|
||||
return result
|
||||
}
|
||||
|
||||
// IsDisjoint two map are disjoint if they have no keys in common
|
||||
// IsDisjoint two map are disjoint if they have no keys in common.
|
||||
// Play: https://go.dev/play/p/N9qgYg_Ho6f
|
||||
func IsDisjoint[K comparable, V any](mapA, mapB map[K]V) bool {
|
||||
for k := range mapA {
|
||||
if _, ok := mapB[k]; ok {
|
||||
|
||||
181
maputil/map_example_test.go
Normal file
181
maputil/map_example_test.go
Normal file
@@ -0,0 +1,181 @@
|
||||
package maputil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
)
|
||||
|
||||
func ExampleKeys() {
|
||||
m := map[int]string{
|
||||
1: "a",
|
||||
2: "a",
|
||||
3: "b",
|
||||
4: "c",
|
||||
5: "d",
|
||||
}
|
||||
|
||||
keys := Keys(m)
|
||||
sort.Ints(keys)
|
||||
|
||||
fmt.Println(keys)
|
||||
|
||||
// Output:
|
||||
// [1 2 3 4 5]
|
||||
}
|
||||
|
||||
func ExampleValues() {
|
||||
m := map[int]string{
|
||||
1: "a",
|
||||
2: "a",
|
||||
3: "b",
|
||||
4: "c",
|
||||
5: "d",
|
||||
}
|
||||
|
||||
values := Values(m)
|
||||
sort.Strings(values)
|
||||
|
||||
fmt.Println(values)
|
||||
|
||||
// Output:
|
||||
// [a a b c d]
|
||||
}
|
||||
|
||||
func ExampleMerge() {
|
||||
m1 := map[int]string{
|
||||
1: "a",
|
||||
2: "b",
|
||||
}
|
||||
m2 := map[int]string{
|
||||
1: "c",
|
||||
3: "d",
|
||||
}
|
||||
|
||||
result := Merge(m1, m2)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// map[1:c 2:b 3:d]
|
||||
}
|
||||
|
||||
func ExampleForEach() {
|
||||
m := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
"d": 4,
|
||||
}
|
||||
|
||||
var sum int
|
||||
ForEach(m, func(_ string, value int) {
|
||||
sum += value
|
||||
})
|
||||
|
||||
fmt.Println(sum)
|
||||
|
||||
// Output:
|
||||
// 10
|
||||
}
|
||||
|
||||
func ExampleFilter() {
|
||||
m := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
"d": 4,
|
||||
"e": 5,
|
||||
}
|
||||
|
||||
isEven := func(_ string, value int) bool {
|
||||
return value%2 == 0
|
||||
}
|
||||
|
||||
result := Filter(m, isEven)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// map[b:2 d:4]
|
||||
}
|
||||
|
||||
func ExampleIntersect() {
|
||||
m1 := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
}
|
||||
|
||||
m2 := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 6,
|
||||
"d": 7,
|
||||
}
|
||||
|
||||
m3 := map[string]int{
|
||||
"a": 1,
|
||||
"b": 9,
|
||||
"e": 9,
|
||||
}
|
||||
|
||||
result1 := Intersect(m1)
|
||||
result2 := Intersect(m1, m2)
|
||||
result3 := Intersect(m1, m2, m3)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// map[a:1 b:2 c:3]
|
||||
// map[a:1 b:2]
|
||||
// map[a:1]
|
||||
}
|
||||
|
||||
func ExampleMinus() {
|
||||
m1 := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
}
|
||||
|
||||
m2 := map[string]int{
|
||||
"a": 11,
|
||||
"b": 22,
|
||||
"d": 33,
|
||||
}
|
||||
|
||||
result := Minus(m1, m2)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// map[c:3]
|
||||
}
|
||||
|
||||
func ExampleIsDisjoint() {
|
||||
m1 := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
}
|
||||
|
||||
m2 := map[string]int{
|
||||
"d": 22,
|
||||
}
|
||||
|
||||
m3 := map[string]int{
|
||||
"a": 22,
|
||||
}
|
||||
|
||||
result1 := IsDisjoint(m1, m2)
|
||||
result2 := IsDisjoint(m1, m3)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
@@ -10,10 +10,11 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/duke-git/lancet/v2/lancetconstraints"
|
||||
"golang.org/x/exp/constraints"
|
||||
)
|
||||
|
||||
// Exponent calculate x^n
|
||||
// Exponent calculate x^n.
|
||||
// Play: https://go.dev/play/p/uF3HGNPk8wr
|
||||
func Exponent(x, n int64) int64 {
|
||||
if n == 0 {
|
||||
return 1
|
||||
@@ -28,7 +29,8 @@ func Exponent(x, n int64) int64 {
|
||||
return t * t
|
||||
}
|
||||
|
||||
// Fibonacci calculate fibonacci number before n
|
||||
// Fibonacci calculate fibonacci number before n.
|
||||
// Play: https://go.dev/play/p/IscseUNMuUc
|
||||
func Fibonacci(first, second, n int) int {
|
||||
if n <= 0 {
|
||||
return 0
|
||||
@@ -42,7 +44,8 @@ func Fibonacci(first, second, n int) int {
|
||||
}
|
||||
}
|
||||
|
||||
// Factorial calculate x!
|
||||
// Factorial calculate x!.
|
||||
// Play: https://go.dev/play/p/tt6LdOK67Nx
|
||||
func Factorial(x uint) uint {
|
||||
var f uint = 1
|
||||
for ; x > 1; x-- {
|
||||
@@ -51,18 +54,19 @@ func Factorial(x uint) uint {
|
||||
return f
|
||||
}
|
||||
|
||||
// Percent calculate the percentage of val to total
|
||||
// Percent calculate the percentage of value to total.
|
||||
func Percent(val, total float64, n int) float64 {
|
||||
if total == 0 {
|
||||
return float64(0)
|
||||
}
|
||||
tmp := val / total * 100
|
||||
tmp := val / total
|
||||
result := RoundToFloat(tmp, n)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// RoundToString round up to n decimal places
|
||||
// RoundToString round up to n decimal places.
|
||||
// Play: https://go.dev/play/p/kZwpBRAcllO
|
||||
func RoundToString(x float64, n int) string {
|
||||
tmp := math.Pow(10.0, float64(n))
|
||||
x *= tmp
|
||||
@@ -71,7 +75,8 @@ func RoundToString(x float64, n int) string {
|
||||
return result
|
||||
}
|
||||
|
||||
// RoundToFloat round up to n decimal places
|
||||
// RoundToFloat round up to n decimal places.
|
||||
// Play: https://go.dev/play/p/ghyb528JRJL
|
||||
func RoundToFloat(x float64, n int) float64 {
|
||||
tmp := math.Pow(10.0, float64(n))
|
||||
x *= tmp
|
||||
@@ -79,7 +84,8 @@ func RoundToFloat(x float64, n int) float64 {
|
||||
return x / tmp
|
||||
}
|
||||
|
||||
// TruncRound round off n decimal places
|
||||
// TruncRound round off n decimal places.
|
||||
// Play: https://go.dev/play/p/aumarSHIGzP
|
||||
func TruncRound(x float64, n int) float64 {
|
||||
floatStr := fmt.Sprintf("%."+strconv.Itoa(n+1)+"f", x)
|
||||
temp := strings.Split(floatStr, ".")
|
||||
@@ -93,8 +99,9 @@ func TruncRound(x float64, n int) float64 {
|
||||
return result
|
||||
}
|
||||
|
||||
// Max return max value of params
|
||||
func Max[T lancetconstraints.Number](numbers ...T) T {
|
||||
// Max return max value of numbers.
|
||||
// Play: https://go.dev/play/p/cN8DHI0rTkH
|
||||
func Max[T constraints.Integer | constraints.Float](numbers ...T) T {
|
||||
max := numbers[0]
|
||||
|
||||
for _, v := range numbers {
|
||||
@@ -106,7 +113,8 @@ func Max[T lancetconstraints.Number](numbers ...T) T {
|
||||
return max
|
||||
}
|
||||
|
||||
// MaxBy search the maximum value of a slice using the given comparator function.
|
||||
// MaxBy return the maximum value of a slice using the given comparator function.
|
||||
// Play: https://go.dev/play/p/pbe2MT-7DV2
|
||||
func MaxBy[T any](slice []T, comparator func(T, T) bool) T {
|
||||
var max T
|
||||
|
||||
@@ -127,8 +135,9 @@ func MaxBy[T any](slice []T, comparator func(T, T) bool) T {
|
||||
return max
|
||||
}
|
||||
|
||||
// Min return min value of params
|
||||
func Min[T lancetconstraints.Number](numbers ...T) T {
|
||||
// Min return min value of numbers.
|
||||
// Play: https://go.dev/play/p/21BER_mlGUj
|
||||
func Min[T constraints.Integer | constraints.Float](numbers ...T) T {
|
||||
min := numbers[0]
|
||||
|
||||
for _, v := range numbers {
|
||||
@@ -140,7 +149,8 @@ func Min[T lancetconstraints.Number](numbers ...T) T {
|
||||
return min
|
||||
}
|
||||
|
||||
// MinBy search the minimum value of a slice using the given comparator function.
|
||||
// MinBy return the minimum value of a slice using the given comparator function.
|
||||
// Play: https://go.dev/play/p/XuJDKrDdglW
|
||||
func MinBy[T any](slice []T, comparator func(T, T) bool) T {
|
||||
var min T
|
||||
|
||||
@@ -161,8 +171,9 @@ func MinBy[T any](slice []T, comparator func(T, T) bool) T {
|
||||
return min
|
||||
}
|
||||
|
||||
// Average return average value of params
|
||||
func Average[T lancetconstraints.Number](numbers ...T) T {
|
||||
// Average return average value of numbers.
|
||||
// Play: https://go.dev/play/p/Vv7LBwER-pz
|
||||
func Average[T constraints.Integer | constraints.Float](numbers ...T) T {
|
||||
var sum T
|
||||
n := T(len(numbers))
|
||||
|
||||
|
||||
187
mathutil/mathutil_exmaple_test.go
Normal file
187
mathutil/mathutil_exmaple_test.go
Normal file
@@ -0,0 +1,187 @@
|
||||
package mathutil
|
||||
|
||||
import "fmt"
|
||||
|
||||
func ExampleExponent() {
|
||||
result1 := Exponent(10, 0)
|
||||
result2 := Exponent(10, 1)
|
||||
result3 := Exponent(10, 2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 10
|
||||
// 100
|
||||
}
|
||||
|
||||
func ExampleFibonacci() {
|
||||
result1 := Fibonacci(1, 1, 1)
|
||||
result2 := Fibonacci(1, 1, 2)
|
||||
result3 := Fibonacci(1, 1, 5)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 1
|
||||
// 5
|
||||
}
|
||||
|
||||
func ExampleFactorial() {
|
||||
result1 := Factorial(1)
|
||||
result2 := Factorial(2)
|
||||
result3 := Factorial(3)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 6
|
||||
}
|
||||
|
||||
func ExamplePercent() {
|
||||
result1 := Percent(1, 2, 2)
|
||||
result2 := Percent(0.1, 0.3, 2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 0.5
|
||||
// 0.33
|
||||
}
|
||||
|
||||
func ExampleRoundToFloat() {
|
||||
result1 := RoundToFloat(0.124, 2)
|
||||
result2 := RoundToFloat(0.125, 2)
|
||||
result3 := RoundToFloat(0.125, 3)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 0.12
|
||||
// 0.13
|
||||
// 0.125
|
||||
}
|
||||
|
||||
func ExampleRoundToString() {
|
||||
result1 := RoundToString(0.124, 2)
|
||||
result2 := RoundToString(0.125, 2)
|
||||
result3 := RoundToString(0.125, 3)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 0.12
|
||||
// 0.13
|
||||
// 0.125
|
||||
}
|
||||
|
||||
func ExampleTruncRound() {
|
||||
result1 := TruncRound(0.124, 2)
|
||||
result2 := TruncRound(0.125, 2)
|
||||
result3 := TruncRound(0.125, 3)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 0.12
|
||||
// 0.12
|
||||
// 0.125
|
||||
}
|
||||
|
||||
func ExampleAverage() {
|
||||
result1 := Average(1, 2)
|
||||
result2 := RoundToFloat(Average(1.2, 1.4), 1)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 1.3
|
||||
}
|
||||
|
||||
func ExampleMax() {
|
||||
result1 := Max(1, 2, 3)
|
||||
result2 := Max(1.2, 1.4, 1.1, 1.4)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
// 1.4
|
||||
}
|
||||
|
||||
func ExampleMaxBy() {
|
||||
result1 := MaxBy([]string{"a", "ab", "abc"}, func(v1, v2 string) bool {
|
||||
return len(v1) > len(v2)
|
||||
})
|
||||
|
||||
result2 := MaxBy([]string{"abd", "abc", "ab"}, func(v1, v2 string) bool {
|
||||
return len(v1) > len(v2)
|
||||
})
|
||||
|
||||
result3 := MaxBy([]string{}, func(v1, v2 string) bool {
|
||||
return len(v1) > len(v2)
|
||||
})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// abc
|
||||
// abd
|
||||
//
|
||||
}
|
||||
|
||||
func ExampleMin() {
|
||||
result1 := Min(1, 2, 3)
|
||||
result2 := Min(1.2, 1.4, 1.1, 1.4)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 1.1
|
||||
}
|
||||
|
||||
func ExampleMinBy() {
|
||||
result1 := MinBy([]string{"a", "ab", "abc"}, func(v1, v2 string) bool {
|
||||
return len(v1) < len(v2)
|
||||
})
|
||||
|
||||
result2 := MinBy([]string{"ab", "ac", "abc"}, func(v1, v2 string) bool {
|
||||
return len(v1) < len(v2)
|
||||
})
|
||||
|
||||
result3 := MinBy([]string{}, func(v1, v2 string) bool {
|
||||
return len(v1) < len(v2)
|
||||
})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// a
|
||||
// ab
|
||||
//
|
||||
}
|
||||
@@ -35,8 +35,8 @@ func TestFactorial(t *testing.T) {
|
||||
func TestPercent(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestPercent")
|
||||
|
||||
assert.Equal(float64(50), Percent(1, 2, 2))
|
||||
assert.Equal(float64(33.33), Percent(0.1, 0.3, 2))
|
||||
assert.Equal(0.5, Percent(1, 2, 2))
|
||||
assert.Equal(0.33, Percent(0.1, 0.3, 2))
|
||||
}
|
||||
|
||||
func TestRoundToFloat(t *testing.T) {
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
@@ -108,7 +108,11 @@ func (client *HttpClient) SendRequest(request *HttpRequest) (*http.Response, err
|
||||
|
||||
client.setTLS(rawUrl)
|
||||
client.setHeader(req, request.Headers)
|
||||
client.setQueryParam(req, rawUrl, request.QueryParams)
|
||||
|
||||
err = client.setQueryParam(req, rawUrl, request.QueryParams)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if request.FormData != nil {
|
||||
client.setFormData(req, request.FormData)
|
||||
@@ -177,7 +181,7 @@ func (client *HttpClient) setQueryParam(req *http.Request, reqUrl string, queryP
|
||||
|
||||
func (client *HttpClient) setFormData(req *http.Request, values url.Values) {
|
||||
formData := []byte(values.Encode())
|
||||
req.Body = ioutil.NopCloser(bytes.NewReader(formData))
|
||||
req.Body = io.NopCloser(bytes.NewReader(formData))
|
||||
req.ContentLength = int64(len(formData))
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package netutil
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@@ -32,7 +32,10 @@ func TestHttpClient_Get(t *testing.T) {
|
||||
}
|
||||
|
||||
var todo Todo
|
||||
httpClient.DecodeResponse(resp, &todo)
|
||||
err = httpClient.DecodeResponse(resp, &todo)
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
}
|
||||
|
||||
assert.Equal(1, todo.Id)
|
||||
}
|
||||
@@ -58,7 +61,7 @@ func TestHttpClent_Post(t *testing.T) {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
body, _ := ioutil.ReadAll(resp.Body)
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
t.Log("response: ", resp.StatusCode, string(body))
|
||||
}
|
||||
|
||||
@@ -90,6 +93,6 @@ func TestStructToUrlValues(t *testing.T) {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
body, _ := ioutil.ReadAll(resp.Body)
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
t.Log("response: ", string(body))
|
||||
}
|
||||
|
||||
@@ -2,8 +2,9 @@ package netutil
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"log"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
@@ -20,7 +21,7 @@ func TestHttpGet(t *testing.T) {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
body, _ := ioutil.ReadAll(resp.Body)
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
t.Log("response: ", resp.StatusCode, string(body))
|
||||
}
|
||||
|
||||
@@ -40,7 +41,7 @@ func TestHttpPost(t *testing.T) {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
body, _ := ioutil.ReadAll(resp.Body)
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
t.Log("response: ", resp.StatusCode, string(body))
|
||||
}
|
||||
|
||||
@@ -50,23 +51,20 @@ func TestHttpPostFormData(t *testing.T) {
|
||||
// "Content-Type": "application/x-www-form-urlencoded",
|
||||
"Content-Type": "multipart/form-data",
|
||||
}
|
||||
type Todo struct {
|
||||
UserId int `json:"userId"`
|
||||
Title string `json:"title"`
|
||||
}
|
||||
// postData := url.Values{}
|
||||
// postData.Add("userId", "1")
|
||||
// postData.Add("title", "TestAddToDo")
|
||||
|
||||
postData := make(map[string]string)
|
||||
postData["userId"] = "1"
|
||||
postData["title"] = "title"
|
||||
postData := url.Values{}
|
||||
postData.Add("userId", "1")
|
||||
postData.Add("title", "TestToDo")
|
||||
|
||||
// postData := make(map[string]string)
|
||||
// postData["userId"] = "1"
|
||||
// postData["title"] = "title"
|
||||
|
||||
resp, err := HttpPost(apiUrl, header, postData, nil)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
body, _ := ioutil.ReadAll(resp.Body)
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
t.Log("response: ", resp.StatusCode, string(body))
|
||||
}
|
||||
|
||||
@@ -87,7 +85,7 @@ func TestHttpPut(t *testing.T) {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
body, _ := ioutil.ReadAll(resp.Body)
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
t.Log("response: ", resp.StatusCode, string(body))
|
||||
}
|
||||
|
||||
@@ -108,7 +106,7 @@ func TestHttpPatch(t *testing.T) {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
body, _ := ioutil.ReadAll(resp.Body)
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
t.Log("response: ", resp.StatusCode, string(body))
|
||||
}
|
||||
|
||||
@@ -118,7 +116,7 @@ func TestHttpDelete(t *testing.T) {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
body, _ := ioutil.ReadAll(resp.Body)
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
t.Log("response: ", resp.StatusCode, string(body))
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ package netutil
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@@ -55,7 +55,7 @@ func GetPublicIpInfo() (*PublicIpInfo, error) {
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package netutil
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
@@ -173,7 +173,7 @@ func setBodyByte(req *http.Request, body any) error {
|
||||
if body != nil {
|
||||
switch b := body.(type) {
|
||||
case []byte:
|
||||
req.Body = ioutil.NopCloser(bytes.NewReader(b))
|
||||
req.Body = io.NopCloser(bytes.NewReader(b))
|
||||
req.ContentLength = int64(len(b))
|
||||
default:
|
||||
return errors.New("body type should be []byte")
|
||||
|
||||
@@ -19,7 +19,8 @@ const (
|
||||
LETTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
)
|
||||
|
||||
// RandInt generate random int between min and max, maybe min, not be max
|
||||
// RandInt generate random int between min and max, maybe min, not be max.
|
||||
// Play: https://go.dev/play/p/pXyyAAI5YxD
|
||||
func RandInt(min, max int) int {
|
||||
if min == max {
|
||||
return min
|
||||
@@ -28,10 +29,12 @@ func RandInt(min, max int) int {
|
||||
min, max = max, min
|
||||
}
|
||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
|
||||
return r.Intn(max-min) + min
|
||||
}
|
||||
|
||||
// RandBytes generate random byte slice
|
||||
// RandBytes generate random byte slice.
|
||||
// Play: https://go.dev/play/p/EkiLESeXf8d
|
||||
func RandBytes(length int) []byte {
|
||||
if length < 1 {
|
||||
return []byte{}
|
||||
@@ -41,45 +44,54 @@ func RandBytes(length int) []byte {
|
||||
if _, err := io.ReadFull(crand.Reader, b); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// RandString generate random string
|
||||
// RandString generate random string of specified length.
|
||||
// Play: https://go.dev/play/p/W2xvRUXA7Mi
|
||||
func RandString(length int) string {
|
||||
return random(LETTERS, length)
|
||||
}
|
||||
|
||||
// RandUpper generate a random upper case string
|
||||
// RandUpper generate a random upper case string.
|
||||
// Play: https://go.dev/play/p/29QfOh0DVuh
|
||||
func RandUpper(length int) string {
|
||||
return random(UPPER_LETTERS, length)
|
||||
}
|
||||
|
||||
// RandLower generate a random lower case string
|
||||
// RandLower generate a random lower case string.
|
||||
// Play: https://go.dev/play/p/XJtZ471cmtI
|
||||
func RandLower(length int) string {
|
||||
return random(LOWER_LETTERS, length)
|
||||
}
|
||||
|
||||
// RandNumeral generate a random numeral string
|
||||
// RandNumeral generate a random numeral string of specified length.
|
||||
// Play: https://go.dev/play/p/g4JWVpHsJcf
|
||||
func RandNumeral(length int) string {
|
||||
return random(NUMERAL, length)
|
||||
}
|
||||
|
||||
// RandNumeralOrLetter generate a random numeral or letter string
|
||||
// RandNumeralOrLetter generate a random numeral or letter string.
|
||||
// Play: https://go.dev/play/p/19CEQvpx2jD
|
||||
func RandNumeralOrLetter(length int) string {
|
||||
return random(NUMERAL+LETTERS, length)
|
||||
}
|
||||
|
||||
// random generate a random string based on given string range
|
||||
// random generate a random string based on given string range.
|
||||
func random(s string, length int) string {
|
||||
b := make([]byte, length)
|
||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
|
||||
for i := range b {
|
||||
b[i] = s[r.Int63()%int64(len(s))]
|
||||
}
|
||||
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// UUIdV4 generate a random UUID of version 4 according to RFC 4122
|
||||
// UUIdV4 generate a random UUID of version 4 according to RFC 4122.
|
||||
// Play: https://go.dev/play/p/_Z9SFmr28ft
|
||||
func UUIdV4() (string, error) {
|
||||
uuid := make([]byte, 16)
|
||||
|
||||
|
||||
126
random/random_example_test.go
Normal file
126
random/random_example_test.go
Normal file
@@ -0,0 +1,126 @@
|
||||
package random
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
func ExampleRandInt() {
|
||||
|
||||
result := RandInt(1, 10)
|
||||
|
||||
if result >= 1 && result < 10 {
|
||||
fmt.Println("ok")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// ok
|
||||
}
|
||||
|
||||
func ExampleRandBytes() {
|
||||
bytes := RandBytes(4)
|
||||
|
||||
fmt.Println(len(bytes))
|
||||
|
||||
// Output:
|
||||
// 4
|
||||
}
|
||||
|
||||
func ExampleRandString() {
|
||||
pattern := `^[a-zA-Z]+$`
|
||||
reg := regexp.MustCompile(pattern)
|
||||
|
||||
s := RandString(6)
|
||||
|
||||
result1 := reg.MatchString(s)
|
||||
result2 := len(s)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// 6
|
||||
}
|
||||
|
||||
func ExampleRandUpper() {
|
||||
pattern := `^[A-Z]+$`
|
||||
reg := regexp.MustCompile(pattern)
|
||||
|
||||
s := RandUpper(6)
|
||||
|
||||
result1 := reg.MatchString(s)
|
||||
result2 := len(s)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// 6
|
||||
}
|
||||
|
||||
func ExampleRandLower() {
|
||||
pattern := `^[a-z]+$`
|
||||
reg := regexp.MustCompile(pattern)
|
||||
|
||||
s := RandLower(6)
|
||||
|
||||
result1 := reg.MatchString(s)
|
||||
result2 := len(s)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// 6
|
||||
}
|
||||
|
||||
func ExampleRandNumeral() {
|
||||
pattern := `^[0-9]+$`
|
||||
reg := regexp.MustCompile(pattern)
|
||||
|
||||
s := RandNumeral(6)
|
||||
|
||||
result1 := reg.MatchString(s)
|
||||
result2 := len(s)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// 6
|
||||
}
|
||||
|
||||
func ExampleRandNumeralOrLetter() {
|
||||
pattern := `^[0-9a-zA-Z]+$`
|
||||
reg := regexp.MustCompile(pattern)
|
||||
|
||||
s := RandNumeralOrLetter(6)
|
||||
|
||||
result1 := reg.MatchString(s)
|
||||
result2 := len(s)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// 6
|
||||
}
|
||||
|
||||
func ExampleUUIdV4() {
|
||||
pattern := `^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$`
|
||||
reg := regexp.MustCompile(pattern)
|
||||
|
||||
s, _ := UUIdV4()
|
||||
|
||||
result := reg.MatchString(s)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
}
|
||||
@@ -68,6 +68,7 @@ func TestRandInt(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestRandInt")
|
||||
|
||||
r1 := RandInt(1, 10)
|
||||
t.Log(r1)
|
||||
assert.GreaterOrEqual(r1, 1)
|
||||
assert.Less(r1, 10)
|
||||
|
||||
|
||||
@@ -34,21 +34,24 @@ type RetryFunc func() error
|
||||
// Option is for adding retry config
|
||||
type Option func(*RetryConfig)
|
||||
|
||||
// RetryTimes set times of retry
|
||||
// RetryTimes set times of retry.
|
||||
// Play: https://go.dev/play/p/ssfVeU2SwLO
|
||||
func RetryTimes(n uint) Option {
|
||||
return func(rc *RetryConfig) {
|
||||
rc.retryTimes = n
|
||||
}
|
||||
}
|
||||
|
||||
// RetryDuration set duration of retries
|
||||
// RetryDuration set duration of retries.
|
||||
// Play: https://go.dev/play/p/nk2XRmagfVF
|
||||
func RetryDuration(d time.Duration) Option {
|
||||
return func(rc *RetryConfig) {
|
||||
rc.retryDuration = d
|
||||
}
|
||||
}
|
||||
|
||||
// Context set retry context config
|
||||
// Context set retry context config.
|
||||
// Play: https://go.dev/play/p/xnAOOXv9GkS
|
||||
func Context(ctx context.Context) Option {
|
||||
return func(rc *RetryConfig) {
|
||||
rc.context = ctx
|
||||
@@ -56,7 +59,8 @@ func Context(ctx context.Context) Option {
|
||||
}
|
||||
|
||||
// Retry executes the retryFunc repeatedly until it was successful or canceled by the context
|
||||
// The default times of retries is 5 and the default duration between retries is 3 seconds
|
||||
// The default times of retries is 5 and the default duration between retries is 3 seconds.
|
||||
// Play: https://go.dev/play/p/nk2XRmagfVF
|
||||
func Retry(retryFunc RetryFunc, opts ...Option) error {
|
||||
config := &RetryConfig{
|
||||
retryTimes: DefaultRetryTimes,
|
||||
|
||||
93
retry/retry_example_test.go
Normal file
93
retry/retry_example_test.go
Normal file
@@ -0,0 +1,93 @@
|
||||
package retry
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func ExampleContext() {
|
||||
ctx, cancel := context.WithCancel(context.TODO())
|
||||
|
||||
number := 0
|
||||
increaseNumber := func() error {
|
||||
number++
|
||||
if number > 3 {
|
||||
cancel()
|
||||
}
|
||||
return errors.New("error occurs")
|
||||
}
|
||||
|
||||
Retry(increaseNumber,
|
||||
RetryDuration(time.Microsecond*50),
|
||||
Context(ctx),
|
||||
)
|
||||
|
||||
fmt.Println(number)
|
||||
|
||||
// Output:
|
||||
// 4
|
||||
}
|
||||
|
||||
func ExampleRetryDuration() {
|
||||
number := 0
|
||||
increaseNumber := func() error {
|
||||
number++
|
||||
if number == 3 {
|
||||
return nil
|
||||
}
|
||||
return errors.New("error occurs")
|
||||
}
|
||||
|
||||
err := Retry(increaseNumber, RetryDuration(time.Microsecond*50))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(number)
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
}
|
||||
|
||||
func ExampleRetryTimes() {
|
||||
number := 0
|
||||
|
||||
increaseNumber := func() error {
|
||||
number++
|
||||
if number == 3 {
|
||||
return nil
|
||||
}
|
||||
return errors.New("error occurs")
|
||||
}
|
||||
|
||||
err := Retry(increaseNumber, RetryTimes(2))
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// function retry.ExampleRetryTimes.func1 run failed after 2 times retry
|
||||
}
|
||||
|
||||
func ExampleRetry() {
|
||||
number := 0
|
||||
increaseNumber := func() error {
|
||||
number++
|
||||
if number == 3 {
|
||||
return nil
|
||||
}
|
||||
return errors.New("error occurs")
|
||||
}
|
||||
|
||||
err := Retry(increaseNumber, RetryDuration(time.Microsecond*50))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(number)
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
}
|
||||
198
slice/slice.go
198
slice/slice.go
@@ -10,11 +10,20 @@ import (
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/duke-git/lancet/v2/lancetconstraints"
|
||||
"golang.org/x/exp/constraints"
|
||||
)
|
||||
|
||||
// Contain check if the target value is in the slice or not
|
||||
// Create a static variable to store the hash table.
|
||||
// This variable has the same lifetime as the entire program and can be shared by functions that are called more than once.
|
||||
var (
|
||||
memoryHashMap = make(map[string]map[any]int)
|
||||
memoryHashCounter = make(map[string]int)
|
||||
)
|
||||
|
||||
// Contain check if the target value is in the slice or not.
|
||||
// Play: https://go.dev/play/p/_454yEHcNjf
|
||||
func Contain[T comparable](slice []T, target T) bool {
|
||||
for _, item := range slice {
|
||||
if item == target {
|
||||
@@ -25,7 +34,8 @@ func Contain[T comparable](slice []T, target T) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// ContainSubSlice check if the slice contain a given subslice or not
|
||||
// ContainSubSlice check if the slice contain a given subslice or not.
|
||||
// Play: https://go.dev/play/p/bcuQ3UT6Sev
|
||||
func ContainSubSlice[T comparable](slice, subSlice []T) bool {
|
||||
for _, v := range subSlice {
|
||||
if !Contain(slice, v) {
|
||||
@@ -36,7 +46,8 @@ func ContainSubSlice[T comparable](slice, subSlice []T) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Chunk creates a slice of elements split into groups the length of size
|
||||
// Chunk creates a slice of elements split into groups the length of size.
|
||||
// Play: https://go.dev/play/p/b4Pou5j2L_C
|
||||
func Chunk[T any](slice []T, size int) [][]T {
|
||||
result := [][]T{}
|
||||
|
||||
@@ -55,14 +66,15 @@ func Chunk[T any](slice []T, size int) [][]T {
|
||||
}
|
||||
|
||||
return result
|
||||
|
||||
}
|
||||
|
||||
// Compact creates an slice with all falsey values removed. The values false, nil, 0, and "" are falsey
|
||||
// Compact creates an slice with all falsey values removed. The values false, nil, 0, and "" are falsey.
|
||||
// Play: https://go.dev/play/p/pO5AnxEr3TK
|
||||
func Compact[T comparable](slice []T) []T {
|
||||
var zero T
|
||||
|
||||
result := []T{}
|
||||
|
||||
for _, v := range slice {
|
||||
if v != zero {
|
||||
result = append(result, v)
|
||||
@@ -73,6 +85,7 @@ func Compact[T comparable](slice []T) []T {
|
||||
}
|
||||
|
||||
// Concat creates a new slice concatenating slice with any additional slices.
|
||||
// Play: https://go.dev/play/p/gPt-q7zr5mk
|
||||
func Concat[T any](slice []T, slices ...[]T) []T {
|
||||
result := append([]T{}, slice...)
|
||||
|
||||
@@ -83,7 +96,8 @@ func Concat[T any](slice []T, slices ...[]T) []T {
|
||||
return result
|
||||
}
|
||||
|
||||
// Difference creates an slice of whose element in slice but not in comparedSlice
|
||||
// Difference creates an slice of whose element in slice but not in comparedSlice.
|
||||
// Play: https://go.dev/play/p/VXvadzLzhDa
|
||||
func Difference[T comparable](slice, comparedSlice []T) []T {
|
||||
result := []T{}
|
||||
|
||||
@@ -98,7 +112,8 @@ 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,
|
||||
// like lodash.js differenceBy: https://lodash.com/docs/4.17.15#differenceBy.
|
||||
// Play: https://go.dev/play/p/DiivgwM5OnC
|
||||
func DifferenceBy[T comparable](slice []T, comparedSlice []T, iteratee func(index int, item T) T) []T {
|
||||
orginSliceAfterMap := Map(slice, iteratee)
|
||||
comparedSliceAfterMap := Map(comparedSlice, iteratee)
|
||||
@@ -113,7 +128,10 @@ func DifferenceBy[T comparable](slice []T, comparedSlice []T, iteratee func(inde
|
||||
return result
|
||||
}
|
||||
|
||||
//DifferenceWith accepts comparator which is invoked to compare elements of slice to values. The order and references of result values are determined by the first slice. The comparator is invoked with two arguments: (arrVal, othVal).
|
||||
// DifferenceWith accepts comparator which is invoked to compare elements of slice to values.
|
||||
// The order and references of result values are determined by the first slice.
|
||||
// The comparator is invoked with two arguments: (arrVal, othVal).
|
||||
// Play: https://go.dev/play/p/v2U2deugKuV
|
||||
func DifferenceWith[T any](slice []T, comparedSlice []T, comparator func(item1, item2 T) bool) []T {
|
||||
result := make([]T, 0)
|
||||
|
||||
@@ -138,7 +156,8 @@ func DifferenceWith[T any](slice []T, comparedSlice []T, comparator func(item1,
|
||||
return result
|
||||
}
|
||||
|
||||
// Equal checks if two slices are equal: the same length and all elements' order and value are equal
|
||||
// Equal checks if two slices are equal: the same length and all elements' order and value are equal.
|
||||
// Play: https://go.dev/play/p/WcRQJ37ifPa
|
||||
func Equal[T comparable](slice1, slice2 []T) bool {
|
||||
if len(slice1) != len(slice2) {
|
||||
return false
|
||||
@@ -153,7 +172,8 @@ func Equal[T comparable](slice1, slice2 []T) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// EqualWith checks if two slices are equal with comparator func
|
||||
// EqualWith checks if two slices are equal with comparator func.
|
||||
// Play: https://go.dev/play/p/b9iygtgsHI1
|
||||
func EqualWith[T, U any](slice1 []T, slice2 []U, comparator func(T, U) bool) bool {
|
||||
if len(slice1) != len(slice2) {
|
||||
return false
|
||||
@@ -169,6 +189,7 @@ func EqualWith[T, U any](slice1 []T, slice2 []U, comparator func(T, U) bool) boo
|
||||
}
|
||||
|
||||
// Every return true if all of the values in the slice pass the predicate function.
|
||||
// Play: https://go.dev/play/p/R8U6Sl-j8cD
|
||||
func Every[T any](slice []T, predicate func(index int, item T) bool) bool {
|
||||
for i, v := range slice {
|
||||
if !predicate(i, v) {
|
||||
@@ -179,7 +200,8 @@ func Every[T any](slice []T, predicate func(index int, item T) bool) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// None return true if all the values in the slice mismatch the criteria
|
||||
// None return true if all the values in the slice mismatch the criteria.
|
||||
// Play: https://go.dev/play/p/KimdalUlC-T
|
||||
func None[T any](slice []T, predicate func(index int, item T) bool) bool {
|
||||
l := 0
|
||||
for i, v := range slice {
|
||||
@@ -192,6 +214,7 @@ func None[T any](slice []T, predicate func(index int, item T) bool) bool {
|
||||
}
|
||||
|
||||
// Some return true if any of the values in the list pass the predicate function.
|
||||
// Play: https://go.dev/play/p/4pO9Xf9NDGS
|
||||
func Some[T any](slice []T, predicate func(index int, item T) bool) bool {
|
||||
for i, v := range slice {
|
||||
if predicate(i, v) {
|
||||
@@ -202,7 +225,8 @@ func Some[T any](slice []T, predicate func(index int, item T) bool) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Filter iterates over elements of slice, returning an slice of all elements pass the predicate function
|
||||
// Filter iterates over elements of slice, returning an slice of all elements pass the predicate function.
|
||||
// Play: https://go.dev/play/p/SdPna-7qK4T
|
||||
func Filter[T any](slice []T, predicate func(index int, item T) bool) []T {
|
||||
result := make([]T, 0)
|
||||
|
||||
@@ -215,7 +239,8 @@ func Filter[T any](slice []T, predicate func(index int, item T) bool) []T {
|
||||
return result
|
||||
}
|
||||
|
||||
// Count returns the number of occurrences of the given item in the slice
|
||||
// Count returns the number of occurrences of the given item in the slice.
|
||||
// Play: https://go.dev/play/p/Mj4oiEnQvRJ
|
||||
func Count[T comparable](slice []T, item T) int {
|
||||
count := 0
|
||||
|
||||
@@ -228,7 +253,8 @@ func Count[T comparable](slice []T, item T) int {
|
||||
return count
|
||||
}
|
||||
|
||||
// CountBy iterates over elements of slice with predicate function, returns the number of all matched elements
|
||||
// CountBy iterates over elements of slice with predicate function, returns the number of all matched elements.
|
||||
// Play: https://go.dev/play/p/tHOccTMDZCC
|
||||
func CountBy[T any](slice []T, predicate func(index int, item T) bool) int {
|
||||
count := 0
|
||||
|
||||
@@ -241,7 +267,8 @@ func CountBy[T any](slice []T, predicate func(index int, item T) bool) int {
|
||||
return count
|
||||
}
|
||||
|
||||
// GroupBy iterate over elements of the slice, each element will be group by criteria, returns two slices
|
||||
// GroupBy iterate over elements of the slice, each element will be group by criteria, returns two slices.
|
||||
// Play: https://go.dev/play/p/QVkPxzPR0iA
|
||||
func GroupBy[T any](slice []T, groupFn func(index int, item T) bool) ([]T, []T) {
|
||||
if len(slice) == 0 {
|
||||
return make([]T, 0), make([]T, 0)
|
||||
@@ -263,6 +290,7 @@ func GroupBy[T any](slice []T, groupFn func(index int, item T) bool) ([]T, []T)
|
||||
}
|
||||
|
||||
// GroupWith return a map composed of keys generated from the resultults of running each element of slice thru iteratee.
|
||||
// Play: https://go.dev/play/p/ApCvMNTLO8a
|
||||
func GroupWith[T any, U comparable](slice []T, iteratee func(item T) U) map[U][]T {
|
||||
result := make(map[U][]T)
|
||||
|
||||
@@ -278,7 +306,8 @@ func GroupWith[T any, U comparable](slice []T, iteratee func(item T) U) map[U][]
|
||||
}
|
||||
|
||||
// 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
|
||||
// If return T is nil then no items matched the predicate func.
|
||||
// Play: https://go.dev/play/p/CBKeBoHVLgq
|
||||
func Find[T any](slice []T, predicate func(index int, item T) bool) (*T, bool) {
|
||||
index := -1
|
||||
|
||||
@@ -296,8 +325,10 @@ func Find[T any](slice []T, predicate func(index int, item T) bool) (*T, bool) {
|
||||
return &slice[index], true
|
||||
}
|
||||
|
||||
// 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
|
||||
// FindLast iterates over elements of slice from end to begin,
|
||||
// return the first one that passes a truth test on predicate function.
|
||||
// If return T is nil then no items matched the predicate func.
|
||||
// Play: https://go.dev/play/p/FFDPV_j7URd
|
||||
func FindLast[T any](slice []T, predicate func(index int, item T) bool) (*T, bool) {
|
||||
index := -1
|
||||
|
||||
@@ -315,7 +346,8 @@ func FindLast[T any](slice []T, predicate func(index int, item T) bool) (*T, boo
|
||||
return &slice[index], true
|
||||
}
|
||||
|
||||
// Flatten flattens slice with one level
|
||||
// Flatten flattens slice with one level.
|
||||
// Play: https://go.dev/play/p/hYa3cBEevtm
|
||||
func Flatten(slice any) any {
|
||||
sv := sliceValue(slice)
|
||||
|
||||
@@ -342,7 +374,8 @@ func Flatten(slice any) any {
|
||||
return result.Interface()
|
||||
}
|
||||
|
||||
// FlattenDeep flattens slice recursive
|
||||
// FlattenDeep flattens slice recursive.
|
||||
// Play: https://go.dev/play/p/yjYNHPyCFaF
|
||||
func FlattenDeep(slice any) any {
|
||||
sv := sliceValue(slice)
|
||||
st := sliceElemType(sv.Type())
|
||||
@@ -369,7 +402,8 @@ func flattenRecursive(value reflect.Value, result reflect.Value) reflect.Value {
|
||||
return result
|
||||
}
|
||||
|
||||
// ForEach iterates over elements of slice and invokes function for each element
|
||||
// ForEach iterates over elements of slice and invokes function for each element.
|
||||
// Play: https://go.dev/play/p/DrPaa4YsHRF
|
||||
func ForEach[T any](slice []T, iteratee func(index int, item T)) {
|
||||
for i, v := range slice {
|
||||
iteratee(i, v)
|
||||
@@ -377,6 +411,7 @@ func ForEach[T any](slice []T, iteratee func(index int, item T)) {
|
||||
}
|
||||
|
||||
// Map creates an slice of values by running each element of slice thru iteratee function.
|
||||
// Play: https://go.dev/play/p/biaTefqPquw
|
||||
func Map[T any, U any](slice []T, iteratee func(index int, item T) U) []U {
|
||||
result := make([]U, len(slice), cap(slice))
|
||||
|
||||
@@ -388,6 +423,7 @@ func Map[T any, U any](slice []T, iteratee func(index int, item T) U) []U {
|
||||
}
|
||||
|
||||
// Reduce creates an slice of values by running each element of slice thru iteratee function.
|
||||
// Play: https://go.dev/play/p/_RfXJJWIsIm
|
||||
func Reduce[T any](slice []T, iteratee func(index int, item1, item2 T) T, initial T) T {
|
||||
if len(slice) == 0 {
|
||||
return initial
|
||||
@@ -405,7 +441,8 @@ func Reduce[T any](slice []T, iteratee func(index int, item1, item2 T) T, initia
|
||||
return result
|
||||
}
|
||||
|
||||
// Replace returns a copy of the slice with the first n non-overlapping instances of old replaced by new
|
||||
// Replace returns a copy of the slice with the first n non-overlapping instances of old replaced by new.
|
||||
// Play: https://go.dev/play/p/P5mZp7IhOFo
|
||||
func Replace[T comparable](slice []T, old T, new T, n int) []T {
|
||||
result := make([]T, len(slice))
|
||||
copy(result, slice)
|
||||
@@ -421,11 +458,13 @@ func Replace[T comparable](slice []T, old T, new T, n int) []T {
|
||||
}
|
||||
|
||||
// ReplaceAll returns a copy of the slice with all non-overlapping instances of old replaced by new.
|
||||
// Play: https://go.dev/play/p/CzqXMsuYUrx
|
||||
func ReplaceAll[T comparable](slice []T, old T, new T) []T {
|
||||
return Replace(slice, old, new, -1)
|
||||
}
|
||||
|
||||
// Repeat creates a slice with length n whose elements are param `item`.
|
||||
// Play: https://go.dev/play/p/1CbOmtgILUU
|
||||
func Repeat[T any](item T, n int) []T {
|
||||
result := make([]T, n)
|
||||
|
||||
@@ -437,7 +476,8 @@ func Repeat[T any](item T, n int) []T {
|
||||
}
|
||||
|
||||
// InterfaceSlice convert param to slice of interface.
|
||||
// This function is deprecated, use generics feature of go1.18+ for replacement
|
||||
// This function is deprecated, use generics feature of go1.18+ for replacement.
|
||||
// Play: https://go.dev/play/p/FdQXF0Vvqs-
|
||||
func InterfaceSlice(slice any) []any {
|
||||
sv := sliceValue(slice)
|
||||
if sv.IsNil() {
|
||||
@@ -453,7 +493,8 @@ func InterfaceSlice(slice any) []any {
|
||||
}
|
||||
|
||||
// StringSlice convert param to slice of string.
|
||||
// This function is deprecated, use generics feature of go1.18+ for replacement
|
||||
// This function is deprecated, use generics feature of go1.18+ for replacement.
|
||||
// Play: https://go.dev/play/p/W0TZDWCPFcI
|
||||
func StringSlice(slice any) []string {
|
||||
v := sliceValue(slice)
|
||||
|
||||
@@ -470,7 +511,8 @@ func StringSlice(slice any) []string {
|
||||
}
|
||||
|
||||
// IntSlice convert param to slice of int.
|
||||
// This function is deprecated, use generics feature of go1.18+ for replacement
|
||||
// This function is deprecated, use generics feature of go1.18+ for replacement.
|
||||
// Play: https://go.dev/play/p/UQDj-on9TGN
|
||||
func IntSlice(slice any) []int {
|
||||
sv := sliceValue(slice)
|
||||
|
||||
@@ -487,6 +529,7 @@ func IntSlice(slice any) []int {
|
||||
}
|
||||
|
||||
// DeleteAt delete the element of slice from start index to end index - 1.
|
||||
// Play: https://go.dev/play/p/pJ-d6MUWcvK
|
||||
func DeleteAt[T any](slice []T, start int, end ...int) []T {
|
||||
size := len(slice)
|
||||
|
||||
@@ -516,7 +559,8 @@ func DeleteAt[T any](slice []T, start int, end ...int) []T {
|
||||
return slice
|
||||
}
|
||||
|
||||
// Drop creates a slice with `n` elements dropped from the beginning when n > 0, or `n` elements dropped from the ending when n < 0
|
||||
// Drop creates a slice with `n` elements dropped from the beginning when n > 0, or `n` elements dropped from the ending when n < 0.
|
||||
// Play: https://go.dev/play/p/pJ-d6MUWcvK
|
||||
func Drop[T any](slice []T, n int) []T {
|
||||
size := len(slice)
|
||||
|
||||
@@ -536,6 +580,7 @@ func Drop[T any](slice []T, n int) []T {
|
||||
}
|
||||
|
||||
// InsertAt insert the value or other slice into slice at index.
|
||||
// Play: https://go.dev/play/p/hMLNxPEGJVE
|
||||
func InsertAt[T any](slice []T, index int, value any) []T {
|
||||
size := len(slice)
|
||||
|
||||
@@ -557,6 +602,7 @@ func InsertAt[T any](slice []T, index int, value any) []T {
|
||||
}
|
||||
|
||||
// UpdateAt update the slice element at index.
|
||||
// Play: https://go.dev/play/p/f3mh2KloWVm
|
||||
func UpdateAt[T any](slice []T, index int, value T) []T {
|
||||
size := len(slice)
|
||||
|
||||
@@ -569,6 +615,7 @@ func UpdateAt[T any](slice []T, index int, value T) []T {
|
||||
}
|
||||
|
||||
// Unique remove duplicate elements in slice.
|
||||
// Play: https://go.dev/play/p/AXw0R3ZTE6a
|
||||
func Unique[T comparable](slice []T) []T {
|
||||
result := []T{}
|
||||
|
||||
@@ -590,6 +637,7 @@ func Unique[T comparable](slice []T) []T {
|
||||
}
|
||||
|
||||
// UniqueBy call iteratee func with every item of slice, then remove duplicated.
|
||||
// Play: https://go.dev/play/p/UR323iZLDpv
|
||||
func UniqueBy[T comparable](slice []T, iteratee func(item T) T) []T {
|
||||
result := []T{}
|
||||
|
||||
@@ -602,6 +650,7 @@ func UniqueBy[T comparable](slice []T, iteratee func(item T) T) []T {
|
||||
}
|
||||
|
||||
// Union creates a slice of unique elements, in order, from all given slices.
|
||||
// Play: https://go.dev/play/p/hfXV1iRIZOf
|
||||
func Union[T comparable](slices ...[]T) []T {
|
||||
result := []T{}
|
||||
contain := map[T]struct{}{}
|
||||
@@ -618,7 +667,8 @@ func Union[T comparable](slices ...[]T) []T {
|
||||
return result
|
||||
}
|
||||
|
||||
// UnionBy is like Union, what's more it accepts iteratee which is invoked for each element of each slice
|
||||
// UnionBy is like Union, what's more it accepts iteratee which is invoked for each element of each slice.
|
||||
// Play: https://go.dev/play/p/HGKHfxKQsFi
|
||||
func UnionBy[T any, V comparable](predicate func(item T) V, slices ...[]T) []T {
|
||||
result := []T{}
|
||||
contain := map[V]struct{}{}
|
||||
@@ -636,7 +686,8 @@ func UnionBy[T any, V comparable](predicate func(item T) V, slices ...[]T) []T {
|
||||
return result
|
||||
}
|
||||
|
||||
// Merge all given slices into one slice
|
||||
// Merge all given slices into one slice.
|
||||
// Play: https://go.dev/play/p/lbjFp784r9N
|
||||
func Merge[T any](slices ...[]T) []T {
|
||||
result := make([]T, 0)
|
||||
|
||||
@@ -648,6 +699,7 @@ func Merge[T any](slices ...[]T) []T {
|
||||
}
|
||||
|
||||
// Intersection creates a slice of unique elements that included by all slices.
|
||||
// Play: https://go.dev/play/p/anJXfB5wq_t
|
||||
func Intersection[T comparable](slices ...[]T) []T {
|
||||
if len(slices) == 0 {
|
||||
return []T{}
|
||||
@@ -684,7 +736,8 @@ func Intersection[T comparable](slices ...[]T) []T {
|
||||
return result
|
||||
}
|
||||
|
||||
// SymmetricDifference oppoiste operation of intersection function
|
||||
// SymmetricDifference oppoiste operation of intersection function.
|
||||
// Play: https://go.dev/play/p/h42nJX5xMln
|
||||
func SymmetricDifference[T comparable](slices ...[]T) []T {
|
||||
if len(slices) == 0 {
|
||||
return []T{}
|
||||
@@ -710,26 +763,30 @@ func SymmetricDifference[T comparable](slices ...[]T) []T {
|
||||
return Unique(result)
|
||||
}
|
||||
|
||||
// Reverse return slice of element order is reversed to the given slice
|
||||
// Reverse return slice of element order is reversed to the given slice.
|
||||
// Play: https://go.dev/play/p/8uI8f1lwNrQ
|
||||
func Reverse[T any](slice []T) {
|
||||
for i, j := 0, len(slice)-1; i < j; i, j = i+1, j-1 {
|
||||
slice[i], slice[j] = slice[j], slice[i]
|
||||
}
|
||||
}
|
||||
|
||||
// Shuffle creates an slice of shuffled values
|
||||
// Shuffle the slice.
|
||||
// Play: https://go.dev/play/p/YHvhnWGU3Ge
|
||||
func Shuffle[T any](slice []T) []T {
|
||||
result := make([]T, len(slice))
|
||||
for i, v := range rand.Perm(len(slice)) {
|
||||
result[i] = slice[v]
|
||||
}
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
|
||||
return result
|
||||
rand.Shuffle(len(slice), func(i, j int) {
|
||||
slice[i], slice[j] = slice[j], slice[i]
|
||||
})
|
||||
|
||||
return slice
|
||||
}
|
||||
|
||||
// Sort sorts a slice of any ordered type(number or string), use quick sort algrithm.
|
||||
// default sort order is ascending (asc), if want descending order, set param `sortOrder` to `desc`
|
||||
func Sort[T lancetconstraints.Ordered](slice []T, sortOrder ...string) {
|
||||
// default sort order is ascending (asc), if want descending order, set param `sortOrder` to `desc`.
|
||||
// Play: https://go.dev/play/p/V9AVjzf_4Fk
|
||||
func Sort[T constraints.Ordered](slice []T, sortOrder ...string) {
|
||||
if len(sortOrder) > 0 && sortOrder[0] == "desc" {
|
||||
quickSort(slice, 0, len(slice)-1, "desc")
|
||||
} else {
|
||||
@@ -738,7 +795,8 @@ func Sort[T lancetconstraints.Ordered](slice []T, sortOrder ...string) {
|
||||
}
|
||||
|
||||
// SortBy sorts the slice in ascending order as determined by the less function.
|
||||
// This sort is not guaranteed to be stable
|
||||
// This sort is not guaranteed to be stable.
|
||||
// Play: https://go.dev/play/p/DAhLQSZEumm
|
||||
func SortBy[T any](slice []T, less func(a, b T) bool) {
|
||||
quickSortBy(slice, 0, len(slice)-1, less)
|
||||
}
|
||||
@@ -746,7 +804,8 @@ func SortBy[T any](slice []T, less func(a, b T) bool) {
|
||||
// SortByField return sorted slice by field
|
||||
// slice element should be struct, field type should be int, uint, string, or bool
|
||||
// default sortType is ascending (asc), if descending order, set sortType to desc
|
||||
// This function is deprecated, use Sort and SortBy for replacement
|
||||
// This function is deprecated, use Sort and SortBy for replacement.
|
||||
// Play: https://go.dev/play/p/fU1prOBP9p1
|
||||
func SortByField(slice any, field string, sortType ...string) error {
|
||||
sv := sliceValue(slice)
|
||||
t := sv.Type().Elem()
|
||||
@@ -816,7 +875,8 @@ func SortByField(slice any, field string, sortType ...string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Without creates a slice excluding all given items
|
||||
// Without creates a slice excluding all given items.
|
||||
// Play: https://go.dev/play/p/bwhEXEypThg
|
||||
func Without[T comparable](slice []T, items ...T) []T {
|
||||
if len(items) == 0 || len(slice) == 0 {
|
||||
return slice
|
||||
@@ -832,18 +892,50 @@ func Without[T comparable](slice []T, items ...T) []T {
|
||||
return result
|
||||
}
|
||||
|
||||
// IndexOf returns the index at which the first occurrence of a item is found in a slice or return -1 if the item cannot be found.
|
||||
func IndexOf[T comparable](slice []T, item T) int {
|
||||
for i, v := range slice {
|
||||
if v == item {
|
||||
return i
|
||||
// IndexOf returns the index at which the first occurrence of an item is found in a slice or return -1 if the item cannot be found.
|
||||
// Play: https://go.dev/play/p/MRN1f0FpABb
|
||||
func IndexOf[T comparable](arr []T, val T) int {
|
||||
limit := 10
|
||||
// gets the hash value of the array as the key of the hash table.
|
||||
key := fmt.Sprintf("%p", arr)
|
||||
// determines whether the hash table is empty. If so, the hash table is created.
|
||||
if memoryHashMap[key] == nil {
|
||||
memoryHashMap[key] = make(map[any]int)
|
||||
// iterate through the array, adding the value and index of each element to the hash table.
|
||||
for i := len(arr) - 1; i >= 0; i-- {
|
||||
memoryHashMap[key][arr[i]] = i
|
||||
}
|
||||
}
|
||||
// update the hash table counter.
|
||||
memoryHashCounter[key]++
|
||||
|
||||
// use the hash table to find the specified value. If found, the index is returned.
|
||||
if index, ok := memoryHashMap[key][val]; ok {
|
||||
// calculate the memory usage of the hash table.
|
||||
size := len(memoryHashMap)
|
||||
// If the memory usage of the hash table exceeds the memory limit, the hash table with the lowest counter is cleared.
|
||||
if size > limit {
|
||||
var minKey string
|
||||
var minVal int
|
||||
for k, v := range memoryHashCounter {
|
||||
if k == key {
|
||||
continue
|
||||
}
|
||||
if minVal == 0 || v < minVal {
|
||||
minKey = k
|
||||
minVal = v
|
||||
}
|
||||
}
|
||||
delete(memoryHashMap, minKey)
|
||||
delete(memoryHashCounter, minKey)
|
||||
}
|
||||
return index
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// LastIndexOf returns the index at which the last occurrence of the item is found in a slice or return -1 if the then cannot be found.
|
||||
// Play: https://go.dev/play/p/DokM4cf1IKH
|
||||
func LastIndexOf[T comparable](slice []T, item T) int {
|
||||
for i := len(slice) - 1; i > 0; i-- {
|
||||
if item == slice[i] {
|
||||
@@ -854,7 +946,8 @@ func LastIndexOf[T comparable](slice []T, item T) int {
|
||||
return -1
|
||||
}
|
||||
|
||||
// ToSlicePointer returns a pointer to the slices of a variable parameter transformation
|
||||
// ToSlicePointer returns a pointer to the slices of a variable parameter transformation.
|
||||
// Play: https://go.dev/play/p/gx4tr6_VXSF
|
||||
func ToSlicePointer[T any](items ...T) []*T {
|
||||
result := make([]*T, len(items))
|
||||
for i := range items {
|
||||
@@ -864,7 +957,8 @@ func ToSlicePointer[T any](items ...T) []*T {
|
||||
return result
|
||||
}
|
||||
|
||||
// ToSlice returns a slices of a variable parameter transformation
|
||||
// ToSlice returns a slices of a variable parameter transformation.
|
||||
// Play: https://go.dev/play/p/YzbzVq5kscN
|
||||
func ToSlice[T any](items ...T) []T {
|
||||
result := make([]T, len(items))
|
||||
copy(result, items)
|
||||
@@ -872,7 +966,8 @@ func ToSlice[T any](items ...T) []T {
|
||||
return result
|
||||
}
|
||||
|
||||
// AppendIfAbsent only absent append the item
|
||||
// AppendIfAbsent only absent append the item.
|
||||
// Play: https://go.dev/play/p/KcC1QXQ-RkL
|
||||
func AppendIfAbsent[T comparable](slice []T, item T) []T {
|
||||
if !Contain(slice, item) {
|
||||
slice = append(slice, item)
|
||||
@@ -880,7 +975,8 @@ func AppendIfAbsent[T comparable](slice []T, item T) []T {
|
||||
return slice
|
||||
}
|
||||
|
||||
// KeyBy converts a slice to a map based on a callback function
|
||||
// KeyBy converts a slice to a map based on a callback function.
|
||||
// Play: https://go.dev/play/p/uXod2LWD1Kg
|
||||
func KeyBy[T any, U comparable](slice []T, iteratee func(item T) U) map[U]T {
|
||||
result := make(map[U]T, len(slice))
|
||||
|
||||
|
||||
761
slice/slice_example_test.go
Normal file
761
slice/slice_example_test.go
Normal file
@@ -0,0 +1,761 @@
|
||||
package slice
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func ExampleContain() {
|
||||
result1 := Contain([]string{"a", "b", "c"}, "a")
|
||||
result2 := Contain([]int{1, 2, 3}, 4)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleContainSubSlice() {
|
||||
result1 := ContainSubSlice([]string{"a", "b", "c"}, []string{"a", "b"})
|
||||
result2 := ContainSubSlice([]string{"a", "b", "c"}, []string{"a", "d"})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleChunk() {
|
||||
arr := []string{"a", "b", "c", "d", "e"}
|
||||
|
||||
result1 := Chunk(arr, 1)
|
||||
result2 := Chunk(arr, 2)
|
||||
result3 := Chunk(arr, 3)
|
||||
result4 := Chunk(arr, 4)
|
||||
result5 := Chunk(arr, 5)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
|
||||
// Output:
|
||||
// [[a] [b] [c] [d] [e]]
|
||||
// [[a b] [c d] [e]]
|
||||
// [[a b c] [d e]]
|
||||
// [[a b c d] [e]]
|
||||
// [[a b c d e]]
|
||||
}
|
||||
|
||||
func ExampleCompact() {
|
||||
result1 := Compact([]int{0})
|
||||
result2 := Compact([]int{0, 1, 2, 3})
|
||||
result3 := Compact([]string{"", "a", "b", "0"})
|
||||
result4 := Compact([]bool{false, true, true})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// []
|
||||
// [1 2 3]
|
||||
// [a b 0]
|
||||
// [true true]
|
||||
}
|
||||
|
||||
func ExampleConcat() {
|
||||
result1 := Concat([]int{1, 2}, []int{3, 4})
|
||||
result2 := Concat([]string{"a", "b"}, []string{"c"}, []string{"d"})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// [1 2 3 4]
|
||||
// [a b c d]
|
||||
}
|
||||
|
||||
func ExampleDifference() {
|
||||
slice1 := []int{1, 2, 3, 4, 5}
|
||||
slice2 := []int{4, 5, 6}
|
||||
|
||||
result := Difference(slice1, slice2)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [1 2 3]
|
||||
}
|
||||
|
||||
func ExampleDifferenceBy() {
|
||||
slice1 := []int{1, 2, 3, 4, 5} //after add one: 2 3 4 5 6
|
||||
slice2 := []int{3, 4, 5} //after add one: 4 5 6
|
||||
|
||||
addOne := func(i int, v int) int {
|
||||
return v + 1
|
||||
}
|
||||
|
||||
result := DifferenceBy(slice1, slice2, addOne)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [1 2]
|
||||
}
|
||||
|
||||
func ExampleDifferenceWith() {
|
||||
slice1 := []int{1, 2, 3, 4, 5}
|
||||
slice2 := []int{4, 5, 6, 7, 8}
|
||||
|
||||
isDouble := func(v1, v2 int) bool {
|
||||
return v2 == 2*v1
|
||||
}
|
||||
|
||||
result := DifferenceWith(slice1, slice2, isDouble)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [1 5]
|
||||
}
|
||||
|
||||
func ExampleEqual() {
|
||||
slice1 := []int{1, 2, 3}
|
||||
slice2 := []int{1, 2, 3}
|
||||
slice3 := []int{1, 3, 2}
|
||||
|
||||
result1 := Equal(slice1, slice2)
|
||||
result2 := Equal(slice1, slice3)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleEqualWith() {
|
||||
slice1 := []int{1, 2, 3}
|
||||
slice2 := []int{2, 4, 6}
|
||||
|
||||
isDouble := func(a, b int) bool {
|
||||
return b == a*2
|
||||
}
|
||||
|
||||
result := EqualWith(slice1, slice2, isDouble)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleEvery() {
|
||||
nums := []int{1, 2, 3, 5}
|
||||
|
||||
isEven := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
|
||||
result := Every(nums, isEven)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleNone() {
|
||||
nums := []int{1, 3, 5}
|
||||
|
||||
isEven := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
|
||||
result := None(nums, isEven)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleSome() {
|
||||
nums := []int{1, 2, 3, 5}
|
||||
|
||||
isEven := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
|
||||
result := Some(nums, isEven)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleFilter() {
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
|
||||
isEven := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
|
||||
result := Filter(nums, isEven)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [2 4]
|
||||
}
|
||||
|
||||
func ExampleCount() {
|
||||
nums := []int{1, 2, 3, 3, 4}
|
||||
|
||||
result1 := Count(nums, 1)
|
||||
result2 := Count(nums, 3)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
}
|
||||
|
||||
func ExampleCountBy() {
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
|
||||
isEven := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
|
||||
result := CountBy(nums, isEven)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 2
|
||||
}
|
||||
|
||||
func ExampleGroupBy() {
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
|
||||
isEven := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
|
||||
even, odd := GroupBy(nums, isEven)
|
||||
|
||||
fmt.Println(even)
|
||||
fmt.Println(odd)
|
||||
|
||||
// Output:
|
||||
// [2 4]
|
||||
// [1 3 5]
|
||||
}
|
||||
|
||||
func ExampleGroupWith() {
|
||||
nums := []float64{6.1, 4.2, 6.3}
|
||||
|
||||
floor := func(num float64) float64 {
|
||||
return math.Floor(num)
|
||||
}
|
||||
|
||||
result := GroupWith(nums, floor) //map[float64][]float64
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// map[4:[4.2] 6:[6.1 6.3]]
|
||||
}
|
||||
|
||||
func ExampleFind() {
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
|
||||
isEven := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
|
||||
result, ok := Find(nums, isEven)
|
||||
|
||||
fmt.Println(*result)
|
||||
fmt.Println(ok)
|
||||
|
||||
// Output:
|
||||
// 2
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleFindLast() {
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
|
||||
isEven := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
|
||||
result, ok := FindLast(nums, isEven)
|
||||
|
||||
fmt.Println(*result)
|
||||
fmt.Println(ok)
|
||||
|
||||
// Output:
|
||||
// 4
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleFlatten() {
|
||||
arrs := [][][]string{{{"a", "b"}}, {{"c", "d"}}}
|
||||
|
||||
result := Flatten(arrs)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [[a b] [c d]]
|
||||
}
|
||||
|
||||
func ExampleFlattenDeep() {
|
||||
arrs := [][][]string{{{"a", "b"}}, {{"c", "d"}}}
|
||||
|
||||
result := FlattenDeep(arrs)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [a b c d]
|
||||
}
|
||||
|
||||
func ExampleForEach() {
|
||||
nums := []int{1, 2, 3}
|
||||
|
||||
var result []int
|
||||
addOne := func(_ int, v int) {
|
||||
result = append(result, v+1)
|
||||
}
|
||||
|
||||
ForEach(nums, addOne)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [2 3 4]
|
||||
}
|
||||
|
||||
func ExampleMap() {
|
||||
nums := []int{1, 2, 3}
|
||||
|
||||
addOne := func(_ int, v int) int {
|
||||
return v + 1
|
||||
}
|
||||
|
||||
result := Map(nums, addOne)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [2 3 4]
|
||||
}
|
||||
|
||||
func ExampleReduce() {
|
||||
nums := []int{1, 2, 3}
|
||||
|
||||
sum := func(_ int, v1, v2 int) int {
|
||||
return v1 + v2
|
||||
}
|
||||
|
||||
result := Reduce(nums, sum, 0)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 6
|
||||
}
|
||||
|
||||
func ExampleReplace() {
|
||||
strs := []string{"a", "b", "c", "a"}
|
||||
|
||||
result1 := Replace(strs, "a", "x", 0)
|
||||
result2 := Replace(strs, "a", "x", 1)
|
||||
result3 := Replace(strs, "a", "x", 2)
|
||||
result4 := Replace(strs, "a", "x", 3)
|
||||
result5 := Replace(strs, "a", "x", -1)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
|
||||
// Output:
|
||||
// [a b c a]
|
||||
// [x b c a]
|
||||
// [x b c x]
|
||||
// [x b c x]
|
||||
// [x b c x]
|
||||
}
|
||||
|
||||
func ExampleReplaceAll() {
|
||||
result := ReplaceAll([]string{"a", "b", "c", "a"}, "a", "x")
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [x b c x]
|
||||
}
|
||||
|
||||
func ExampleRepeat() {
|
||||
result := Repeat("a", 3)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [a a a]
|
||||
}
|
||||
|
||||
func ExampleInterfaceSlice() {
|
||||
strs := []string{"a", "b", "c"}
|
||||
|
||||
result := InterfaceSlice(strs) //[]interface{}{"a", "b", "c"}
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [a b c]
|
||||
}
|
||||
|
||||
func ExampleStringSlice() {
|
||||
strs := []interface{}{"a", "b", "c"}
|
||||
|
||||
result := StringSlice(strs) //[]string{"a", "b", "c"}
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [a b c]
|
||||
}
|
||||
|
||||
func ExampleIntSlice() {
|
||||
nums := []interface{}{1, 2, 3}
|
||||
|
||||
result := IntSlice(nums) //[]int{1, 2, 3}
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [1 2 3]
|
||||
}
|
||||
|
||||
func ExampleDeleteAt() {
|
||||
result1 := DeleteAt([]string{"a", "b", "c"}, -1)
|
||||
result2 := DeleteAt([]string{"a", "b", "c"}, 0)
|
||||
result3 := DeleteAt([]string{"a", "b", "c"}, 0, 2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// [a b c]
|
||||
// [b c]
|
||||
// [c]
|
||||
}
|
||||
|
||||
func ExampleDrop() {
|
||||
result1 := Drop([]string{"a", "b", "c"}, 0)
|
||||
result2 := Drop([]string{"a", "b", "c"}, 1)
|
||||
result3 := Drop([]string{"a", "b", "c"}, -1)
|
||||
result4 := Drop([]string{"a", "b", "c"}, 4)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// [a b c]
|
||||
// [b c]
|
||||
// [a b]
|
||||
// []
|
||||
}
|
||||
|
||||
func ExampleInsertAt() {
|
||||
result1 := InsertAt([]string{"a", "b", "c"}, 0, "1")
|
||||
result2 := InsertAt([]string{"a", "b", "c"}, 1, "1")
|
||||
result3 := InsertAt([]string{"a", "b", "c"}, 2, "1")
|
||||
result4 := InsertAt([]string{"a", "b", "c"}, 3, "1")
|
||||
result5 := InsertAt([]string{"a", "b", "c"}, 0, []string{"1", "2", "3"})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
|
||||
// Output:
|
||||
// [1 a b c]
|
||||
// [a 1 b c]
|
||||
// [a b 1 c]
|
||||
// [a b c 1]
|
||||
// [1 2 3 a b c]
|
||||
}
|
||||
|
||||
func ExampleUpdateAt() {
|
||||
result1 := UpdateAt([]string{"a", "b", "c"}, -1, "1")
|
||||
result2 := UpdateAt([]string{"a", "b", "c"}, 0, "1")
|
||||
result3 := UpdateAt([]string{"a", "b", "c"}, 1, "1")
|
||||
result4 := UpdateAt([]string{"a", "b", "c"}, 2, "1")
|
||||
result5 := UpdateAt([]string{"a", "b", "c"}, 3, "1")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
|
||||
// Output:
|
||||
// [a b c]
|
||||
// [1 b c]
|
||||
// [a 1 c]
|
||||
// [a b 1]
|
||||
// [a b c]
|
||||
}
|
||||
|
||||
func ExampleUnique() {
|
||||
result := Unique([]string{"a", "a", "b"})
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [a b]
|
||||
}
|
||||
|
||||
func ExampleUniqueBy() {
|
||||
nums := []int{1, 2, 3, 4, 5, 6}
|
||||
result := UniqueBy(nums, func(val int) int {
|
||||
return val % 3
|
||||
})
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [1 2 0]
|
||||
}
|
||||
|
||||
func ExampleUnion() {
|
||||
nums1 := []int{1, 3, 4, 6}
|
||||
nums2 := []int{1, 2, 5, 6}
|
||||
|
||||
result := Union(nums1, nums2)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [1 3 4 6 2 5]
|
||||
}
|
||||
|
||||
func ExampleUnionBy() {
|
||||
nums := []int{1, 2, 3, 4}
|
||||
|
||||
divideTwo := func(n int) int {
|
||||
return n / 2
|
||||
}
|
||||
result := UnionBy(divideTwo, nums)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [1 2 4]
|
||||
}
|
||||
|
||||
func ExampleMerge() {
|
||||
nums1 := []int{1, 2, 3}
|
||||
nums2 := []int{3, 4}
|
||||
|
||||
result := Merge(nums1, nums2)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [1 2 3 3 4]
|
||||
}
|
||||
|
||||
func ExampleIntersection() {
|
||||
nums1 := []int{1, 2, 3}
|
||||
nums2 := []int{2, 3, 4}
|
||||
|
||||
result := Intersection(nums1, nums2)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [2 3]
|
||||
}
|
||||
|
||||
func ExampleSymmetricDifference() {
|
||||
nums1 := []int{1, 2, 3}
|
||||
nums2 := []int{1, 2, 4}
|
||||
|
||||
result := SymmetricDifference(nums1, nums2)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [3 4]
|
||||
}
|
||||
|
||||
func ExampleReverse() {
|
||||
strs := []string{"a", "b", "c", "d"}
|
||||
|
||||
Reverse(strs)
|
||||
|
||||
fmt.Println(strs)
|
||||
|
||||
// Output:
|
||||
// [d c b a]
|
||||
}
|
||||
|
||||
func ExampleSort() {
|
||||
nums := []int{1, 4, 3, 2, 5}
|
||||
|
||||
Sort(nums)
|
||||
|
||||
fmt.Println(nums)
|
||||
|
||||
// Output:
|
||||
// [1 2 3 4 5]
|
||||
}
|
||||
|
||||
func ExampleSortBy() {
|
||||
type User struct {
|
||||
Name string
|
||||
Age uint
|
||||
}
|
||||
|
||||
users := []User{
|
||||
{Name: "a", Age: 21},
|
||||
{Name: "b", Age: 15},
|
||||
{Name: "c", Age: 100}}
|
||||
|
||||
SortBy(users, func(a, b User) bool {
|
||||
return a.Age < b.Age
|
||||
})
|
||||
|
||||
fmt.Println(users)
|
||||
|
||||
// Output:
|
||||
// [{b 15} {a 21} {c 100}]
|
||||
}
|
||||
|
||||
func ExampleSortByField() {
|
||||
type User struct {
|
||||
Name string
|
||||
Age uint
|
||||
}
|
||||
|
||||
users := []User{
|
||||
{Name: "a", Age: 21},
|
||||
{Name: "b", Age: 15},
|
||||
{Name: "c", Age: 100}}
|
||||
|
||||
err := SortByField(users, "Age", "desc")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(users)
|
||||
|
||||
// Output:
|
||||
// [{c 100} {a 21} {b 15}]
|
||||
}
|
||||
|
||||
func ExampleWithout() {
|
||||
result := Without([]int{1, 2, 3, 4}, 1, 2)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [3 4]
|
||||
}
|
||||
|
||||
func ExampleIndexOf() {
|
||||
strs := []string{"a", "a", "b", "c"}
|
||||
|
||||
result1 := IndexOf(strs, "a")
|
||||
result2 := IndexOf(strs, "d")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
// -1
|
||||
}
|
||||
|
||||
func ExampleLastIndexOf() {
|
||||
strs := []string{"a", "a", "b", "c"}
|
||||
|
||||
result1 := LastIndexOf(strs, "a")
|
||||
result2 := LastIndexOf(strs, "d")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// -1
|
||||
}
|
||||
|
||||
func ExampleToSlice() {
|
||||
result := ToSlice("a", "b", "c")
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [a b c]
|
||||
}
|
||||
|
||||
func ExampleToSlicePointer() {
|
||||
str1 := "a"
|
||||
str2 := "b"
|
||||
|
||||
result := ToSlicePointer(str1, str2)
|
||||
|
||||
expect := []*string{&str1, &str2}
|
||||
|
||||
isEqual := reflect.DeepEqual(result, expect)
|
||||
|
||||
fmt.Println(isEqual)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleAppendIfAbsent() {
|
||||
result1 := AppendIfAbsent([]string{"a", "b"}, "b")
|
||||
result2 := AppendIfAbsent([]string{"a", "b"}, "c")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// [a b]
|
||||
// [a b c]
|
||||
}
|
||||
|
||||
func ExampleKeyBy() {
|
||||
result := KeyBy([]string{"a", "ab", "abc"}, func(str string) int {
|
||||
return len(str)
|
||||
})
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// map[1:a 2:ab 3:abc]
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/duke-git/lancet/v2/lancetconstraints"
|
||||
"golang.org/x/exp/constraints"
|
||||
)
|
||||
|
||||
// sliceValue return the reflect value of a slice
|
||||
@@ -27,7 +27,7 @@ func sliceElemType(reflectType reflect.Type) reflect.Type {
|
||||
}
|
||||
}
|
||||
|
||||
func quickSort[T lancetconstraints.Ordered](slice []T, lowIndex, highIndex int, order string) {
|
||||
func quickSort[T constraints.Ordered](slice []T, lowIndex, highIndex int, order string) {
|
||||
if lowIndex < highIndex {
|
||||
p := partitionOrderedSlice(slice, lowIndex, highIndex, order)
|
||||
quickSort(slice, lowIndex, p-1, order)
|
||||
@@ -36,7 +36,7 @@ func quickSort[T lancetconstraints.Ordered](slice []T, lowIndex, highIndex int,
|
||||
}
|
||||
|
||||
// partitionOrderedSlice split ordered slice into two parts for quick sort
|
||||
func partitionOrderedSlice[T lancetconstraints.Ordered](slice []T, lowIndex, highIndex int, order string) int {
|
||||
func partitionOrderedSlice[T constraints.Ordered](slice []T, lowIndex, highIndex int, order string) int {
|
||||
p := slice[highIndex]
|
||||
i := lowIndex
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user