1
0
mirror of https://github.com/duke-git/lancet.git synced 2026-02-04 21:02:27 +08:00

Compare commits

...

26 Commits

Author SHA1 Message Date
dudaodong
6d4fc981b6 release v2.2.9 2024-02-01 10:03:26 +08:00
dudaodong
4c21fe700c refactor: update StringToBytes logic 2024-01-30 10:46:55 +08:00
pigwantacat
b7370e8ef8 refactor:refactor random function (#164)
Co-authored-by: zhuhebin <zhuhebin@fengtaisec.com>
2024-01-30 10:00:14 +08:00
dudaodong
38920e3be6 fix: fix issue #162 2024-01-29 11:00:50 +08:00
dudaodong
a630a7cda9 refactor: remove struct_internal.go 2024-01-29 10:02:36 +08:00
dudaodong
66dfd9c4fd refactor: refact Comma function 2024-01-25 16:45:17 +08:00
dudaodong
be62aaac9b refactor: update signature of WriteMapsToCsv function
g
2024-01-24 11:54:42 +08:00
dudaodong
e0c9ccbce3 doc: add DeleteRange 2024-01-23 17:27:28 +08:00
dudaodong
d2d1e5a055 feat: refact DeleteAt and add DeleteRange function 2024-01-22 15:34:35 +08:00
dudaodong
bbc58c7e46 fix: fix the map key order issue of WriteMapsToCsv 2024-01-22 11:10:02 +08:00
dudaodong
ac2ecceaec refactor: refact reduce function 2024-01-03 10:46:28 +08:00
dudaodong
a06bb8ee6a fix: fix unit test for WriteMapsToCsv 2024-01-01 18:32:41 +08:00
dudaodong
27b5702fd3 fix: fix unit test for WriteMapsToCsv 2024-01-01 17:51:32 +08:00
dudaodong
b2c3fa0ab8 fix: fix golint issue 2024-01-01 17:43:11 +08:00
dudaodong
4afc838937 doc: add doc for WriteMapsToCsv 2024-01-01 17:40:32 +08:00
colorcrow
3482f80d1c WriteCsvFile自定义分割符,增加map切片写入csv,增加追踪函数运行时间的函数 (#157)
* WriteCsvFile now support custom delimiter,Add write map slice to csv

* add trace func time
2024-01-01 16:54:04 +08:00
suacrbah
565f2893b9 feat: add support for seeking and read one line at a time from file (#158)
* feat: add support for seeking and read one line at a time from file

* feat: add support for calculating folder total size

---------

Co-authored-by: Suacrbah <5744580+Suacrbah@user.noreply.gitee.com>
2024-01-01 16:50:54 +08:00
dudaodong
1b1b10d0ee merge main branch 2023-12-29 10:17:04 +08:00
Gregory Koganovskiy
c5c3888ffc Fix typos in README (#154) 2023-12-29 10:12:29 +08:00
duckjiangwei
11214986cc add new func & docs error repair (#153)
* feat: add method IsTargetType()

* docs:document error repair
2023-12-28 10:27:32 +08:00
dudaodong
0bc7b83e59 Merge branch 'main' into v2 2023-12-21 10:03:35 +08:00
duckjiangwei
6225418074 improvement:optimize bubble sort (#152) 2023-12-21 10:02:23 +08:00
dudaodong
ddd265de78 fix: fix comment error 2023-12-19 15:36:07 +08:00
dudaodong
80e48f06ca refactor: rename lancetconstraints package name to constraints 2023-12-16 19:29:06 +08:00
dudaodong
0b976e9a4c fix: fix failed unit test 2023-12-11 15:45:02 +08:00
dudaodong
96320069f4 doc: update for release v2.2.8 2023-12-11 15:30:33 +08:00
50 changed files with 1087 additions and 477 deletions

131
README.md
View File

@@ -4,7 +4,7 @@
<br/>
![Go version](https://img.shields.io/badge/go-%3E%3Dv1.18-9cf)
[![Release](https://img.shields.io/badge/release-2.2.8-green.svg)](https://github.com/duke-git/lancet/releases)
[![Release](https://img.shields.io/badge/release-2.2.9-green.svg)](https://github.com/duke-git/lancet/releases)
[![GoDoc](https://godoc.org/github.com/duke-git/lancet/v2?status.svg)](https://pkg.go.dev/github.com/duke-git/lancet/v2)
[![Go Report Card](https://goreportcard.com/badge/github.com/duke-git/lancet/v2)](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
[![test](https://github.com/duke-git/lancet/actions/workflows/codecov.yml/badge.svg?branch=main&event=push)](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
@@ -32,7 +32,7 @@
### Note:
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>
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 were rewritten with generics of go1.18.</b>
```go
go get github.com/duke-git/lancet/v2 // will install latest version of v2.x.x
@@ -201,10 +201,10 @@ import "github.com/duke-git/lancet/v2/concurrency"
- **<big>OrDone</big>** : read a channel into another channel, will close until cancel context.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/concurrency.md#OrDone)]
[[play](https://go.dev/play/p/lm_GoS6aDjo)]
- **<big>Repeat</big>** : create channel, put values into the channel repeatly until cancel the context.
- **<big>Repeat</big>** : create channel, put values into the channel repeatedly until cancel the context.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/concurrency.md#Repeat)]
[[play](https://go.dev/play/p/k5N_ALVmYjE)]
- **<big>RepeatFn</big>** : create a channel, excutes fn repeatly, and put the result into the channel, until close context.
- **<big>RepeatFn</big>** : create a channel, executes fn repeatedly, and put the result into the channel, until close context.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/concurrency.md#RepeatFn)]
[[play](https://go.dev/play/p/4J1zAWttP85)]
- **<big>Take</big>** : create a channel whose values are taken from another channel with limit number.
@@ -247,7 +247,7 @@ import "github.com/duke-git/lancet/v2/condition"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/condition.md#TernaryOperator)]
[[play](https://go.dev/play/p/ElllPZY0guT)]
<h3 id="convertor"> 5. Convertor package contains some functions for data convertion. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a> </h3>
<h3 id="convertor"> 5. Convertor package contains some functions for data conversion. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a> </h3>
```go
import "github.com/duke-git/lancet/v2/convertor"
@@ -596,7 +596,7 @@ import "github.com/duke-git/lancet/v2/datetime"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/datetime.md#TimestampNano)]
[[play](https://go.dev/play/p/A9Oq_COrcCF)]
<h3 id="datastructure"> 8. Datastructure package constains some common data structure. eg. list, linklist, stack, queue, set, tree, graph. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
<h3 id="datastructure"> 8. Datastructure package contains some common data structure. eg. list, linklist, stack, queue, set, tree, graph. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
```go
import list "github.com/duke-git/lancet/v2/datastructure/list"
@@ -706,6 +706,8 @@ import "github.com/duke-git/lancet/v2/fileutil"
[[play](https://go.dev/play/p/OExTkhGEd3_u)]
- **<big>WriteCsvFile</big>** : write content to target csv file.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/fileutil.md#WriteCsvFile)]
- **<big>WriteMapsToCsv</big>** : write slice of map to csv file.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/fileutil.md#WriteMapsToCsv)]
[[play](https://go.dev/play/p/dAXm58Q5U1o)]
- **<big>WriteBytesToFile</big>** : write bytes to target file.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/fileutil.md#WriteBytesToFile)]
@@ -754,10 +756,10 @@ import "github.com/duke-git/lancet/v2/function"
#### Function list:
- **<big>After</big>** : return a function that invokes passed funcation once the returned function is called more than n times.
- **<big>After</big>** : return a function that invokes passed function once the returned function is called more than n times.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/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
- **<big>Before</big>** : return a function that invokes passed function once the returned function is called less than n times
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/function.md#Before)]
[[play](https://go.dev/play/p/0HqUDIFZ3IL)]
- **<big>CurryFn</big>** : make a curry function.
@@ -778,7 +780,7 @@ import "github.com/duke-git/lancet/v2/function"
- **<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/en/api/packages/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.
- **<big>Watcher</big>** : Watcher is used for record code execution 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/en/api/packages/function.md#Watcher)]
[[play](https://go.dev/play/p/l2yrOpCLd1I)]
@@ -793,7 +795,7 @@ import "github.com/duke-git/lancet/v2/maputil"
- **<big>MapTo</big>** : quick map any value to struct or any base type.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#MapTo)]
[[play](https://go.dev/play/p/4K7KBEPgS5M)]
- **<big>ForEach</big>** : executes iteratee funcation for every key and value pair in map.
- **<big>ForEach</big>** : executes iteratee function for every key and value pair in map.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/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.
@@ -811,7 +813,7 @@ import "github.com/duke-git/lancet/v2/maputil"
- **<big>OmitByKeys</big>** : the opposite of FilterByKeys, extracts all the map elements which keys are not omitted.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#OmitByKeys)]
[[play](https://go.dev/play/p/jXGrWDBfSRp)]
- **<big>OmitByValues</big>** : the opposite of FilterByValues. remov all elements whose value are in the give slice.
- **<big>OmitByValues</big>** : the opposite of FilterByValues. remove all elements whose value are in the give slice.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#OmitByValues)]
[[play](https://go.dev/play/p/XB7Y10uw20_U)]
- **<big>Intersect</big>** : iterates over maps, return a new map of key and value pairs in all given maps.
@@ -961,7 +963,7 @@ import "github.com/duke-git/lancet/v2/mathutil"
- **<big>Sum</big>** : return sum of passed numbers.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/mathutil.md#Sum)]
[[play](https://go.dev/play/p/1To2ImAMJA7)]
- **<big>Abs</big>** : returns the absolute value of param nubmer.
- **<big>Abs</big>** : returns the absolute value of param number.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/mathutil.md#Sum)]
[[play](https://go.dev/play/p/fsyBh1Os-1d)]
@@ -1012,7 +1014,7 @@ import "github.com/duke-git/lancet/v2/netutil"
- **<big>DecodeResponse</big>** : decode http response into target object.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/netutil.md#DecodeResponse)]
[[play](https://go.dev/play/p/jUSgynekH7G)]
- **<big>StructToUrlValues</big>** : convert struct to url valuse.
- **<big>StructToUrlValues</big>** : convert struct to url values.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/netutil.md#StructToUrlValues)]
[[play](https://go.dev/play/p/pFqMkM40w9z)]
- **<big>HttpGet<sup>deprecated</sup></big>** : send http get request.
@@ -1099,10 +1101,16 @@ import "github.com/duke-git/lancet/v2/random"
[[play](https://go.dev/play/p/uBkRSOz73Ec)]
- **<big>RandSymbolChar</big>** : Generate a random symbol char of specified length.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/random.md#RandSymbolChar)]
[[play](https://go.dev/play/p/Im6ZJxAykOm)]
- **<big>RandFloat</big>** : Generate a random float64 number between [min, max) with specific precision.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/random.md#RandFloat)]
[[play](https://go.dev/play/p/zbD_tuobJtr)]
- **<big>RandFloats</big>** : Generate a slice of random float64 numbers of length n that do not repeat.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/random.md#RandFloats)]
[[play](https://go.dev/play/p/I3yndUQ-rhh)]
<h3 id="retry"> 17. Retry package is for executing a function repeatedly until it was successful or canceled by the context. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
@@ -1151,7 +1159,7 @@ import "github.com/duke-git/lancet/v2/slice"
- **<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/en/api/packages/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.
- **<big>Compact</big>** : creates an slice with all falsy values removed. The values false, nil, 0, and "" are falsy.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#Compact)]
[[play](https://go.dev/play/p/pO5AnxEr3TK)]
- **<big>Concat</big>** : creates a new slice concatenating slice with any additional slices.
@@ -1172,9 +1180,10 @@ import "github.com/duke-git/lancet/v2/slice"
- **<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/en/api/packages/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.
- **<big>DeleteAt</big>** : delete the element of slice at index.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#DeleteAt)]
[[play](https://go.dev/play/p/pJ-d6MUWcvK)]
- **<big>DeleteRange</big>** : delete the element of slice from start index to end indexexclude).
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#DeleteRange)]
- **<big>Drop</big>** : drop n elements from the start of a slice.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#Drop)]
[[play](https://go.dev/play/p/jnPO2yQsT8H)]
@@ -1232,7 +1241,7 @@ import "github.com/duke-git/lancet/v2/slice"
- **<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/en/api/packages/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.
- **<big>GroupWith</big>** : return a map composed of keys generated from the results of running each element of slice thru iteratee.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#GroupWith)]
[[play](https://go.dev/play/p/ApCvMNTLO8a)]
- **<big>IntSlice<sup>deprecated</sup></big>** : convert param to int slice.
@@ -1348,6 +1357,8 @@ import "github.com/duke-git/lancet/v2/slice"
[[play](https://go.dev/play/p/lkQ3Ri2NQhV)]
- **<big>Random</big>** : get a random item of slice, return its index, when slice is empty, return -1.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#Random)]
[[play](https://go.dev/play/p/UzpGQptWppw)]
<h3 id="stream"> 19. Stream package implements a sequence of elements supporting sequential and operations. this package is an experiment to explore if stream in go can work as the way java does. its function is very limited. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
@@ -1369,7 +1380,7 @@ import "github.com/duke-git/lancet/v2/stream"
- **<big>FromRange</big>** : creates a number stream from start to end. both start and end are included. [start, end]
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/stream.md#FromRange)]
[[play](https://go.dev/play/p/9Ex1-zcg-B-)]
- **<big>Generate</big>** : creates a stream where each element is generated by the provided generater function.
- **<big>Generate</big>** : creates a stream where each element is generated by the provided generator function.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/stream.md#Generate)]
[[play](https://go.dev/play/p/rkOWL1yA3j9)]
- **<big>Concat</big>** : creates a lazily concatenated stream whose elements are all the elements of the first stream followed by all the elements of the second stream.
@@ -1414,10 +1425,10 @@ import "github.com/duke-git/lancet/v2/stream"
- **<big>FindLast</big>** : returns the last element of this stream and true, or zero value and false if the stream is empty.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/stream.md#FindLast)]
[[play](https://go.dev/play/p/WZD2rDAW-2h)]
- **<big>Max</big>** : returns the maximum element of this stream according to the provided less function. less fuction: a > b
- **<big>Max</big>** : returns the maximum element of this stream according to the provided less function. less function: a > b
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/stream.md#Max)]
[[play](https://go.dev/play/p/fm-1KOPtGzn)]
- **<big>Min</big>** : returns the minimum element of this stream according to the provided less function. less fuction: a < b
- **<big>Min</big>** : returns the minimum element of this stream according to the provided less function. less function: a < b
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/stream.md#Min)]
[[play](https://go.dev/play/p/vZfIDgGNRe_0)]
- **<big>AllMatch</big>** : returns whether all elements of this stream match the provided predicate.
@@ -1445,29 +1456,31 @@ import "github.com/duke-git/lancet/v2/structs"
#### Function list:
- **<big>New</big>** : creates a `Struct` instance.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/structs/struct.md#New)]
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/struct.md#New)]
- **<big>ToMap</big>** : converts a valid struct to a map.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/structs/struct.md#ToMap)]
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/struct.md#ToMap)]
- **<big>Fields</big>** : get all fields of a given struct, that the fields are abstract struct field.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/structs/struct.md#Fields)]
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/struct.md#Fields)]
- **<big>IsStruct</big>** : check if the struct is valid.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/structs/struct.md#IsStruct)]
- **<big>Tag</big>** : get a `Tag` of the `Field`, `Tag` is a abstract struct field tag
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/structs/field.md#Tag)]
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/struct.md#IsStruct)]
- **<big>Tag</big>** : get a `Tag` of the `Field`, `Tag` is a abstract struct field tag.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/struct.md#Tag)]
- **<big>Name</big>** : get the field name.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/structs/field.md#Name)]
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/struct.md#Name)]
- **<big>Value</big>** : get the `Field` underlying value.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/structs/field.md#Value)]
- **<big>Kind</big>** : get the field's kind
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/structs/field.md#Kind)]
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/struct.md#Value)]
- **<big>Kind</big>** : get the field's kind.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/struct.md#Kind)]
- **<big>IsEmbedded</big>** : check if the field is an embedded field.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/structs/field.md#IsEmbedded)]
- **<big>IsExported</big>** : check if the field is exporte
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/structs/field.md#IsExported)]
- **<big>IsZero</big>** : check if the field is zero value
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/structs/field.md#IsZero)]
- **<big>IsSlice</big>** : check if the field is a slice
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/structs/field.md#IsSlice)]
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/struct.md#IsEmbedded)]
- **<big>IsExported</big>** : check if the field is exported.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/struct.md#IsExported)]
- **<big>IsZero</big>** : check if the field is zero value.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/struct.md#IsZero)]
- **<big>IsSlice</big>** : check if the field is a slice.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/struct.md#IsSlice)]
- **<big>IsTargetType</big>** : check if the field is target type.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/struct.md#IsTargetType)]
<h3 id="strutil"> 21. Strutil package contains some functions to manipulate string. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
@@ -1636,7 +1649,7 @@ import "github.com/duke-git/lancet/v2/tuple"
#### Function list:
- **<big>Tuple2</big>** : represents a 2 elemnets tuple.
- **<big>Tuple2</big>** : represents a 2 elements tuple.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/tuple.md#Tuple2)]
[[play](https://go.dev/play/p/3sHVqBQpLYN)]
- **<big>Tuple2_Unbox</big>** : returns values in Tuple2.
@@ -1648,7 +1661,7 @@ import "github.com/duke-git/lancet/v2/tuple"
- **<big>Unzip2</big>** : create a group of slice from a slice of Tuple2.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/tuple.md#Unzip2)]
[[play](https://go.dev/play/p/KBecr60feXb)]
- **<big>Tuple3</big>** : represents a 3 elemnets tuple.
- **<big>Tuple3</big>** : represents a 3 elements tuple.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/tuple.md#Tuple3)]
[[play](https://go.dev/play/p/FtH2sdCLlCf)]
- **<big>Tuple3_Unbox</big>** : returns values in Tuple3.
@@ -1660,7 +1673,7 @@ import "github.com/duke-git/lancet/v2/tuple"
- **<big>Unzip3</big>** : create a group of slice from a slice of Tuple3.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/tuple.md#Unzip3)]
[[play](https://go.dev/play/p/bba4cpAa7KO)]
- **<big>Tuple4</big>** : represents a 4 elemnets tuple.
- **<big>Tuple4</big>** : represents a 4 elements tuple.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/tuple.md#Tuple4)]
[[play](https://go.dev/play/p/D2EqDz096tk)]
- **<big>Tuple4_Unbox</big>** : returns values in Tuple4.
@@ -1672,7 +1685,7 @@ import "github.com/duke-git/lancet/v2/tuple"
- **<big>Unzip4</big>** : create a group of slice from a slice of Tuple4.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/tuple.md#Unzip4)]
[[play](https://go.dev/play/p/rb8z4gyYSRN)]
- **<big>Tuple5</big>** : represents a 5 elemnets tuple.
- **<big>Tuple5</big>** : represents a 5 elements tuple.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/tuple.md#Tuple5)]
[[play](https://go.dev/play/p/2WndmVxPg-r)]
- **<big>Tuple5_Unbox</big>** : returns values in Tuple4.
@@ -1684,7 +1697,7 @@ import "github.com/duke-git/lancet/v2/tuple"
- **<big>Unzip5</big>** : create a group of slice from a slice of Tuple5.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/tuple.md#Unzip5)]
[[play](https://go.dev/play/p/gyl6vKfhqPb)]
- **<big>Tuple6</big>** : represents a 6 elemnets tuple.
- **<big>Tuple6</big>** : represents a 6 elements tuple.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/tuple.md#Tuple6)]
[[play](https://go.dev/play/p/VjqcCwEJZbs)]
- **<big>Tuple6_Unbox</big>** : returns values in Tuple6.
@@ -1696,7 +1709,7 @@ import "github.com/duke-git/lancet/v2/tuple"
- **<big>Unzip6</big>** : create a group of slice from a slice of Tuple6.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/tuple.md#Unzip6)]
[[play](https://go.dev/play/p/l41XFqCyh5E)]
- **<big>Tuple7</big>** : represents a 7 elemnets tuple.
- **<big>Tuple7</big>** : represents a 7 elements tuple.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/tuple.md#Tuple7)]
[[play](https://go.dev/play/p/dzAgv_Ezub9)]
- **<big>Tuple7_Unbox</big>** : returns values in Tuple7.
@@ -1708,7 +1721,7 @@ import "github.com/duke-git/lancet/v2/tuple"
- **<big>Unzip7</big>** : create a group of slice from a slice of Tuple7.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/tuple.md#Unzip7)]
[[play](https://go.dev/play/p/hws_P1Fr2j3)]
- **<big>Tuple8</big>** : represents a 8 elemnets tuple.
- **<big>Tuple8</big>** : represents a 8 elements tuple.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/tuple.md#Tuple8)]
[[play](https://go.dev/play/p/YA9S0rz3dRz)]
- **<big>Tuple8_Unbox</big>** : returns values in Tuple8.
@@ -1720,7 +1733,7 @@ import "github.com/duke-git/lancet/v2/tuple"
- **<big>Unzip8</big>** : create a group of slice from a slice of Tuple8.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/tuple.md#Unzip8)]
[[play](https://go.dev/play/p/1SndOwGsZB4)]
- **<big>Tuple9</big>** : represents a 9 elemnets tuple.
- **<big>Tuple9</big>** : represents a 9 elements tuple.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/tuple.md#Tuple9)]
[[play](https://go.dev/play/p/yS2NGGtZpQr)]
- **<big>Tuple9_Unbox</big>** : returns values in Tuple9.
@@ -1732,7 +1745,7 @@ import "github.com/duke-git/lancet/v2/tuple"
- **<big>Unzip9</big>** : create a group of slice from a slice of Tuple9.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/tuple.md#Unzip9)]
[[play](https://go.dev/play/p/91-BU_KURSA)]
- **<big>Tuple10</big>** : represents a 10 elemnets tuple.
- **<big>Tuple10</big>** : represents a 10 elements tuple.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/tuple.md#Tuple10)]
[[play](https://go.dev/play/p/799qqZg0hUv)]
- **<big>Tuple10_Unbox</big>** : returns values in Tuple10.
@@ -1864,19 +1877,19 @@ import "github.com/duke-git/lancet/v2/validator"
- **<big>IsJWT</big>** : check if a give string is a valid JSON Web Token (JWT).
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/validator.md#IsJWT)]
[[play](https://go.dev/play/p/R6Op7heJbKI)]
- **<big>IsVisa</big>** : check if a give string is a valid visa card nubmer or not.
- **<big>IsVisa</big>** : check if a give string is a valid visa card number or not.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/validator.md#IsVisa)]
[[play](https://go.dev/play/p/SdS2keOyJsl)]
- **<big>IsMasterCard</big>** : check if a give string is a valid master card nubmer or not.
- **<big>IsMasterCard</big>** : check if a give string is a valid master card number or not.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/validator.md#IsMasterCard)]
[[play](https://go.dev/play/p/CwWBFRrG27b)]
- **<big>IsAmericanExpress</big>** : check if a give string is a valid american expression card nubmer or not.
- **<big>IsAmericanExpress</big>** : check if a give string is a valid american expression card number or not.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/validator.md#IsAmericanExpress)]
[[play](https://go.dev/play/p/HIDFpcOdpkd)]
- **<big>IsUnionPay</big>** : check if a give string is a valid union pay nubmer or not.
- **<big>IsUnionPay</big>** : check if a give string is a valid union pay number or not.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/validator.md#IsUnionPay)]
[[play](https://go.dev/play/p/CUHPEwEITDf)]
- **<big>IsChinaUnionPay</big>** : check if a give string is a valid china union pay nubmer or not.
- **<big>IsChinaUnionPay</big>** : check if a give string is a valid china union pay number or not.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/validator.md#IsChinaUnionPay)]
[[play](https://go.dev/play/p/yafpdxLiymu)]
@@ -1932,22 +1945,6 @@ import "github.com/duke-git/lancet/v2/xerror"
#### [Contributing Guide](./CONTRIBUTING.en-US.md)
## Sponsor
Hello, I am a software developer and have been engaged in development work for 13 years. Love open source software. And be willing to put in the energy for it. I am the creator of project lancet. Since Lancet was released as open source two years ago, it has been used by more than 1,000 internal and external projects. lancet will always be free for all users. Your support is a powerful encouragement for me to continue my struggle. Thanks! You can use WeChat to scans the following QR code or clicks the following sponsor button to initiate sponsorship.
<div style="position: relative;display: inline-block;">
<img src="./docs/public/wechat_pay.png" width="260" height="260"/>
<a href="https://en.liberapay.com/Duke_Du/donate" target="\_blank"><img src="./docs/public/sponsor_btn.png" width="220" height="60"/></a>
</div>
<br/>
<br/>
*Donated funds will be used to maintain [lancet](https://www.golancet.cn/en/) website and pay for cloud server costs. Or just buy me a cup of ☕️ when I'm sleepy writing code.*
## Contributors
Thank you to all the people who contributed to lancet!

View File

@@ -4,7 +4,7 @@
<br/>
![Go version](https://img.shields.io/badge/go-%3E%3Dv1.18-9cf)
[![Release](https://img.shields.io/badge/release-2.2.8-green.svg)](https://github.com/duke-git/lancet/releases)
[![Release](https://img.shields.io/badge/release-2.2.9-green.svg)](https://github.com/duke-git/lancet/releases)
[![GoDoc](https://godoc.org/github.com/duke-git/lancet/v2?status.svg)](https://pkg.go.dev/github.com/duke-git/lancet/v2)
[![Go Report Card](https://goreportcard.com/badge/github.com/duke-git/lancet/v2)](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
[![test](https://github.com/duke-git/lancet/actions/workflows/codecov.yml/badge.svg?branch=main&event=push)](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
@@ -705,8 +705,10 @@ import "github.com/duke-git/lancet/v2/fileutil"
- **<big>ReadCsvFile</big>** : 读取 csv 文件内容到切片。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/fileutil.md#ReadCsvFile)]
[[play](https://go.dev/play/p/OExTkhGEd3_u)]
- **<big>WriteCsvFile</big>** : 向 csv 文件写入内容
- **<big>WriteCsvFile</big>** : 向csv文件写入切片数据
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/fileutil.md#WriteCsvFile)]
- **<big>WriteMapsToCsv</big>** : 将map切片写入csv文件中。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/fileutil.md#WriteMapsToCsv)]
[[play](https://go.dev/play/p/dAXm58Q5U1o)]
- **<big>WriteBytesToFile</big>** : 将 bytes 写入文件。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/fileutil.md#WriteBytesToFile)]
@@ -1100,12 +1102,14 @@ import "github.com/duke-git/lancet/v2/random"
[[play](https://go.dev/play/p/uBkRSOz73Ec)]
- **<big>RandSymbolChar</big>** : 生成给定长度的随机符号字符串。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/random.md#RandSymbolChar)]
[[play](https://go.dev/play/p/uBkRSOz73Ec)]
[[play](https://go.dev/play/p/Im6ZJxAykOm)]
- **<big>RandFloat</big>** : 生成随机float64数字可以指定范围和精度。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/random.md#RandFloat)]
[[play](https://go.dev/play/p/uBkRSOz73Ec)]
[[play](https://go.dev/play/p/zbD_tuobJtr)]
- **<big>RandFloats</big>** : 生成随机float64数字切片可以指定长度范围和精度.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/random.md#RandFloats)]
[[play](https://go.dev/play/p/uBkRSOz73Ec)]
<h3 id="retry"> 17. retry 重试执行函数直到函数运行成功或被 context cancel。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
@@ -1175,9 +1179,10 @@ import "github.com/duke-git/lancet/v2/slice"
- **<big>DifferenceWith</big>** : 接受比较器函数,该比较器被调用以将切片的元素与值进行比较。 结果值的顺序和引用由第一个切片确定。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#DifferenceWith)]
[[play](https://go.dev/play/p/v2U2deugKuV)]
- **<big>DeleteAt</big>** : 删除切片中指定开始索引到结束索引的元素。
- **<big>DeleteAt</big>** : 删除切片中指定索引到的元素。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#DeleteAt)]
[[play](https://go.dev/play/p/pJ-d6MUWcvK)]
- **<big>DeleteRange</big>** : 删除切片中指定开始索引到结束索引的元素。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#DeleteRange)]
- **<big>Drop</big>** : 从切片头部删除 n 个元素。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#Drop)]
[[play](https://go.dev/play/p/jnPO2yQsT8H)]
@@ -1340,7 +1345,6 @@ import "github.com/duke-git/lancet/v2/slice"
- **<big>Without</big>** : 创建一个不包括所有给定值的切片。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#Without)]
[[play](https://go.dev/play/p/bwhEXEypThg)]
- **<big>KeyBy</big>** :将切片每个元素调用函数后转为 map。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#KeyBy)]
[[play](https://go.dev/play/p/uXod2LWD1Kg)]
- **<big>Join</big>** : 用指定的分隔符链接切片元素。
@@ -1351,6 +1355,8 @@ import "github.com/duke-git/lancet/v2/slice"
[[play](https://go.dev/play/p/lkQ3Ri2NQhV)]
- **<big>Random</big>** : 随机返回切片中元素以及下标, 当切片长度为0时返回下标-1。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#Random)]
[[play](https://go.dev/play/p/UzpGQptWppw)]
<h3 id="stream"> 19. stream 流,该包仅验证简单的 stream 实现,功能有限。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
@@ -1449,31 +1455,33 @@ import "github.com/duke-git/lancet/v2/structs"
#### 函数列表:
- **<big>New</big>** : `Struct`结构体的构造函数。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/structs/struct.md#New)]
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/struct.md#New)]
- **<big>ToMap</big>** : 将一个合法的 struct 对象转换为 map[string]any。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/structs/struct.md#ToMap)]
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/struct.md#ToMap)]
- **<big>Fields</big>** : 获取一个 struct 对象的属性列表。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/structs/struct.md#Fields)]
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/struct.md#Fields)]
- **<big>Field</big>** : 根据属性名获取一个 struct 对象的属性。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/structs/struct.md#Fields)]
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/struct.md#Fields)]
- **<big>IsStruct</big>** : 判断是否为一个合法的 struct 对象。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/structs/struct.md#IsStruct)]
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/struct.md#IsStruct)]
- **<big>Tag</big>** : 获取`Field``Tag`,默认的 tag key 是 json。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/structs/field.md#Tag)]
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/struct.md#Tag)]
- **<big>Name</big>** : 获取属性名。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/structs/field.md#Name)]
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/struct.md#Name)]
- **<big>Value</big>** : 获取`Field`属性的值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/structs/field.md#Value)]
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/struct.md#Value)]
- **<big>Kind</big>** : 获取属性 Kind。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/structs/field.md#Kind)]
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/struct.md#Kind)]
- **<big>IsEmbedded</big>** : 判断属性是否为嵌入。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/structs/field.md#IsEmbedded)]
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/struct.md#IsEmbedded)]
- **<big>IsExported</big>** : 判断属性是否导出。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/structs/field.md#IsExported)]
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/struct.md#IsExported)]
- **<big>IsZero</big>** : 判断属性是否为零值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/structs/field.md#IsZero)]
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/struct.md#IsZero)]
- **<big>IsSlice</big>** : 判断属性是否是切片。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/structs/field.md#IsSlice)]
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/struct.md#IsSlice)]
- **<big>IsTargetType</big>** : 判断属性是否是目标类型。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/struct.md#IsTargetType)]
<h3 id="strutil"> 21. strutil 包含字符串处理的相关函数。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
@@ -1938,23 +1946,9 @@ import "github.com/duke-git/lancet/v2/xerror"
#### [贡献代码指南](./CONTRIBUTING.zh-CN.md)
## 赞助
您好,我是一名软件开发者,从事开发工作 13 年。热爱软件开源。并愿意为此付出精力。是开源项目 lancet 的作者。Lancet 自两年前开源发布以来,已有超过 1000 个内外部项目使用。lancet 一直会对所有用户免费。您的支持是对我继续奋斗的有力鼓励。谢谢! 微信扫描以下二维码或点击以下赞助按钮发起赞助。
<div style="position: relative;display: inline-block;">
<img src="./docs/public/wechat_pay.png" width="260" height="260"/>
<a href="https://liberapay.com/Duke_Du/donate" target="\_blank"><img src="./docs/public/sponsor_btn.png" width="220" height="60"/></a>
</div>
<br/>
<br/>
_捐赠的资金将用于后续[lancet](https://www.golancet.cn/)官网的维护和云服务器的费用支付。或者当我写代码困倦时,给我买杯 ☕️。_
## 贡献者
感谢所有为 lancet 贡献过代码的人!
感谢所有为lancet贡献过代码的人
<a href="https://github.com/duke-git/lancet/graphs/contributors">
<img src="https://contrib.rocks/image?repo=duke-git/lancet" />

View File

@@ -4,7 +4,7 @@
// 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"
import "github.com/duke-git/lancet/v2/constraints"
// Search algorithms see https://github.com/TheAlgorithms/Go/tree/master/search
@@ -23,7 +23,7 @@ func LinearSearch[T any](slice []T, target T, equal func(a, b T) bool) int {
// 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 {
func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator constraints.Comparator) int {
if highIndex < lowIndex || len(sortedSlice) == 0 {
return -1
}
@@ -44,7 +44,7 @@ func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, com
// 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 {
func BinaryIterativeSearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator constraints.Comparator) int {
startIndex := lowIndex
endIndex := highIndex

View File

@@ -3,24 +3,29 @@
package algorithm
import "github.com/duke-git/lancet/v2/lancetconstraints"
import "github.com/duke-git/lancet/v2/constraints"
// 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) {
func BubbleSort[T any](slice []T, comparator constraints.Comparator) {
for i := 0; i < len(slice); i++ {
breakTag := false
for j := 0; j < len(slice)-1-i; j++ {
isCurrGreatThanNext := comparator.Compare(slice[j], slice[j+1]) == 1
if isCurrGreatThanNext {
swap(slice, j, j+1)
breakTag = true
}
}
if !breakTag {
break
}
}
}
// 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) {
func InsertionSort[T any](slice []T, comparator constraints.Comparator) {
for i := 0; i < len(slice); i++ {
for j := i; j > 0; j-- {
isPreLessThanCurrent := comparator.Compare(slice[j], slice[j-1]) == -1
@@ -35,7 +40,7 @@ func InsertionSort[T any](slice []T, comparator lancetconstraints.Comparator) {
// 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) {
func SelectionSort[T any](slice []T, comparator constraints.Comparator) {
for i := 0; i < len(slice); i++ {
min := i
for j := i + 1; j < len(slice); j++ {
@@ -49,7 +54,7 @@ func SelectionSort[T any](slice []T, comparator lancetconstraints.Comparator) {
// 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) {
func ShellSort[T any](slice []T, comparator constraints.Comparator) {
size := len(slice)
gap := 1
@@ -69,11 +74,11 @@ func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator) {
// 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) {
func QuickSort[T any](slice []T, comparator constraints.Comparator) {
quickSort(slice, 0, len(slice)-1, comparator)
}
func quickSort[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) {
func quickSort[T any](slice []T, lowIndex, highIndex int, comparator constraints.Comparator) {
if lowIndex < highIndex {
p := partition(slice, lowIndex, highIndex, comparator)
quickSort(slice, lowIndex, p-1, comparator)
@@ -82,7 +87,7 @@ func quickSort[T any](slice []T, lowIndex, highIndex int, comparator lancetconst
}
// partition split slice into two parts
func partition[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int {
func partition[T any](slice []T, lowIndex, highIndex int, comparator constraints.Comparator) int {
p := slice[highIndex]
i := lowIndex
for j := lowIndex; j < highIndex; j++ {
@@ -99,7 +104,7 @@ func partition[T any](slice []T, lowIndex, highIndex int, comparator lancetconst
// 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) {
func HeapSort[T any](slice []T, comparator constraints.Comparator) {
size := len(slice)
for i := size/2 - 1; i >= 0; i-- {
@@ -111,7 +116,7 @@ func HeapSort[T any](slice []T, comparator lancetconstraints.Comparator) {
}
}
func sift[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) {
func sift[T any](slice []T, lowIndex, highIndex int, comparator constraints.Comparator) {
i := lowIndex
j := 2*i + 1
@@ -133,11 +138,11 @@ func sift[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraint
// 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) {
func MergeSort[T any](slice []T, comparator constraints.Comparator) {
mergeSort(slice, 0, len(slice)-1, comparator)
}
func mergeSort[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) {
func mergeSort[T any](slice []T, lowIndex, highIndex int, comparator constraints.Comparator) {
if lowIndex < highIndex {
mid := (lowIndex + highIndex) / 2
mergeSort(slice, lowIndex, mid, comparator)
@@ -146,7 +151,7 @@ func mergeSort[T any](slice []T, lowIndex, highIndex int, comparator lancetconst
}
}
func merge[T any](slice []T, lowIndex, midIndex, highIndex int, comparator lancetconstraints.Comparator) {
func merge[T any](slice []T, lowIndex, midIndex, highIndex int, comparator constraints.Comparator) {
i := lowIndex
j := midIndex + 1
temp := []T{}
@@ -175,7 +180,7 @@ func merge[T any](slice []T, lowIndex, midIndex, highIndex int, comparator lance
// 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 {
func CountSort[T any](slice []T, comparator constraints.Comparator) []T {
size := len(slice)
out := make([]T, size)

View File

@@ -16,7 +16,7 @@ type people struct {
// PeopleAageComparator sort people slice by age field
type peopleAgeComparator struct{}
// Compare implements github.com/duke-git/lancet/v2/lancetconstraints/constraints.go/Comparator
// Compare implements github.com/duke-git/lancet/v2/constraints/constraints.go/Comparator
func (pc *peopleAgeComparator) Compare(v1 any, v2 any) int {
p1, _ := v1.(people)
p2, _ := v2.(people)

View File

@@ -1,8 +1,8 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package lancetconstraints contain some comstomer constraints.
package lancetconstraints
// Package constraints contain some custom interface.
package constraints
// Comparator is for comparing two values
type Comparator interface {

View File

@@ -7,18 +7,18 @@ package datastructure
import (
"fmt"
"github.com/duke-git/lancet/v2/lancetconstraints"
"github.com/duke-git/lancet/v2/constraints"
)
// MaxHeap implements a binary max heap
// type T should implements Compare function in lancetconstraints.Comparator interface.
// type T should implements Compare function in constraints.Comparator interface.
type MaxHeap[T any] struct {
data []T
comparator lancetconstraints.Comparator
comparator constraints.Comparator
}
// NewMaxHeap returns a MaxHeap instance with the given comparator.
func NewMaxHeap[T any](comparator lancetconstraints.Comparator) *MaxHeap[T] {
func NewMaxHeap[T any](comparator constraints.Comparator) *MaxHeap[T] {
return &MaxHeap[T]{
data: make([]T, 0),
comparator: comparator,
@@ -26,7 +26,7 @@ func NewMaxHeap[T any](comparator lancetconstraints.Comparator) *MaxHeap[T] {
}
// BuildMaxHeap builds a MaxHeap instance with data and given comparator.
func BuildMaxHeap[T any](data []T, comparator lancetconstraints.Comparator) *MaxHeap[T] {
func BuildMaxHeap[T any](data []T, comparator constraints.Comparator) *MaxHeap[T] {
heap := &MaxHeap[T]{
data: make([]T, 0, len(data)),
comparator: comparator,

View File

@@ -8,20 +8,20 @@ package datastructure
import (
"errors"
"github.com/duke-git/lancet/v2/lancetconstraints"
"github.com/duke-git/lancet/v2/constraints"
)
// PriorityQueue is a priority queue implemented by binary heap tree
// type T should implements Compare function in lancetconstraints.Comparator interface.
// type T should implements Compare function in constraints.Comparator interface.
type PriorityQueue[T any] struct {
items []T
size int
comparator lancetconstraints.Comparator
comparator constraints.Comparator
}
// NewPriorityQueue return a pointer of PriorityQueue
// param `comparator` is used to compare values in the queue
func NewPriorityQueue[T any](capacity int, comparator lancetconstraints.Comparator) *PriorityQueue[T] {
func NewPriorityQueue[T any](capacity int, comparator constraints.Comparator) *PriorityQueue[T] {
return &PriorityQueue[T]{
items: make([]T, capacity+1),
size: 0,

View File

@@ -7,22 +7,22 @@ package datastructure
import (
"math"
"github.com/duke-git/lancet/v2/constraints"
"github.com/duke-git/lancet/v2/datastructure"
"github.com/duke-git/lancet/v2/lancetconstraints"
)
// BSTree is a binary search tree data structure in which each node has at most two children,
// which are referred to as the left child and the right child.
// In BSTree: leftNode < rootNode < rightNode
// type T should implements Compare function in lancetconstraints.Comparator interface.
// type T should implements Compare function in constraints.Comparator interface.
type BSTree[T any] struct {
root *datastructure.TreeNode[T]
comparator lancetconstraints.Comparator
comparator constraints.Comparator
}
// NewBSTree create a BSTree pointer
// param `comparator` is used to compare values in the tree
func NewBSTree[T any](rootData T, comparator lancetconstraints.Comparator) *BSTree[T] {
func NewBSTree[T any](rootData T, comparator constraints.Comparator) *BSTree[T] {
root := datastructure.NewTreeNode(rootData)
return &BSTree[T]{root, comparator}
}
@@ -87,7 +87,7 @@ func (t *BSTree[T]) HasSubTree(subTree *BSTree[T]) bool {
}
func hasSubTree[T any](superTreeRoot, subTreeRoot *datastructure.TreeNode[T],
comparator lancetconstraints.Comparator) bool {
comparator constraints.Comparator) bool {
result := false
if superTreeRoot != nil && subTreeRoot != nil {

View File

@@ -4,8 +4,8 @@ import (
"fmt"
"math"
"github.com/duke-git/lancet/v2/constraints"
"github.com/duke-git/lancet/v2/datastructure"
"github.com/duke-git/lancet/v2/lancetconstraints"
)
func preOrderTraverse[T any](node *datastructure.TreeNode[T]) []T {
@@ -86,7 +86,7 @@ func levelOrderTraverse[T any](root *datastructure.TreeNode[T], traversal *[]T)
}
}
func insertTreeNode[T any](rootNode, newNode *datastructure.TreeNode[T], comparator lancetconstraints.Comparator) {
func insertTreeNode[T any](rootNode, newNode *datastructure.TreeNode[T], comparator constraints.Comparator) {
if comparator.Compare(newNode.Value, rootNode.Value) == -1 {
if rootNode.Left == nil {
rootNode.Left = newNode
@@ -103,7 +103,7 @@ func insertTreeNode[T any](rootNode, newNode *datastructure.TreeNode[T], compara
}
// todo, delete root node failed
func deleteTreeNode[T any](node *datastructure.TreeNode[T], data T, comparator lancetconstraints.Comparator) *datastructure.TreeNode[T] {
func deleteTreeNode[T any](node *datastructure.TreeNode[T], data T, comparator constraints.Comparator) *datastructure.TreeNode[T] {
if node == nil {
return nil
}
@@ -216,7 +216,7 @@ func calculateDepth[T any](node *datastructure.TreeNode[T], depth int) int {
return max(calculateDepth(node.Left, depth+1), calculateDepth(node.Right, depth+1))
}
func isSubTree[T any](superTreeRoot, subTreeRoot *datastructure.TreeNode[T], comparator lancetconstraints.Comparator) bool {
func isSubTree[T any](superTreeRoot, subTreeRoot *datastructure.TreeNode[T], comparator constraints.Comparator) bool {
if subTreeRoot == nil {
return true
}

View File

@@ -381,3 +381,12 @@ func TimestampNano(timezone ...string) int64 {
return t.UnixNano()
}
// TraceFuncTime: trace the func costed time,just call it at top of the func like `defer TraceFuncTime()()`
func TraceFuncTime() func() {
pre := time.Now()
return func() {
elapsed := time.Since(pre)
fmt.Println("Costs Time:\t", elapsed)
}
}

View File

@@ -43,12 +43,12 @@ import (
### <span id="BubbleSort">BubbleSort</span>
<p>冒泡排序参数comparator需要实现包lancetconstraints.Comparator。</p>
<p>冒泡排序参数comparator需要实现包constraints.Comparator。</p>
<b>函数签名:</b>
```go
func BubbleSort[T any](slice []T, comparator lancetconstraints.Comparator)
func BubbleSort[T any](slice []T, comparator constraints.Comparator)
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/GNdv7Jg2Taj)</span></b>
@@ -91,12 +91,12 @@ func main() {
### <span id="InsertionSort">InsertionSort</span>
<p>插入排序参数comparator需要实现包lancetconstraints.Comparator。</p>
<p>插入排序参数comparator需要实现包constraints.Comparator。</p>
<b>函数签名:</b>
```go
func InsertionSort[T any](slice []T, comparator lancetconstraints.Comparator)
func InsertionSort[T any](slice []T, comparator constraints.Comparator)
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/G5LJiWgJJW6)</span></b>
@@ -117,7 +117,7 @@ type people struct {
// PeopleAageComparator sort people slice by age field
type peopleAgeComparator struct{}
// Compare implements github.com/duke-git/lancet/lancetconstraints/constraints.go/Comparator
// Compare implements github.com/duke-git/lancet/constraints/constraints.go/Comparator
func (pc *peopleAgeComparator) Compare(v1 any, v2 any) int {
p1, _ := v1.(people)
p2, _ := v2.(people)
@@ -154,12 +154,12 @@ func main() {
### <span id="SelectionSort">SelectionSort</span>
<p>选择排序参数comparator需要实现包lancetconstraints.Comparator。</p>
<p>选择排序参数comparator需要实现包constraints.Comparator。</p>
<b>函数签名:</b>
```go
func SelectionSort[T any](slice []T, comparator lancetconstraints.Comparator)
func SelectionSort[T any](slice []T, comparator constraints.Comparator)
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/oXovbkekayS)</span></b>
@@ -202,12 +202,12 @@ func main() {
### <span id="ShellSort">ShellSort</span>
<p>希尔排序参数comparator需要实现包lancetconstraints.Comparator。</p>
<p>希尔排序参数comparator需要实现包constraints.Comparator。</p>
<b>函数签名:</b>
```go
func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator)
func ShellSort[T any](slice []T, comparator constraints.Comparator)
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/3ibkszpJEu3)</span></b>
@@ -250,12 +250,12 @@ func main() {
### <span id="QuickSort">QuickSort</span>
<p>快速排序参数comparator需要实现包lancetconstraints.Comparator。</p>
<p>快速排序参数comparator需要实现包constraints.Comparator。</p>
<b>函数签名:</b>
```go
func QuickSort[T any](slice []T comparator lancetconstraints.Comparator)
func QuickSort[T any](slice []T comparator constraints.Comparator)
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/7Y7c1Elk3ax)</span></b>
@@ -298,12 +298,12 @@ func main() {
### <span id="HeapSort">HeapSort</span>
<p>堆排序参数comparator需要实现包lancetconstraints.Comparator。</p>
<p>堆排序参数comparator需要实现包constraints.Comparator。</p>
<b>函数签名:</b>
```go
func HeapSort[T any](slice []T, comparator lancetconstraints.Comparator)
func HeapSort[T any](slice []T, comparator constraints.Comparator)
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/u6Iwa1VZS_f)</span></b>
@@ -346,12 +346,12 @@ func main() {
### <span id="MergeSort">MergeSort</span>
<p>归并排序参数comparator需要实现包lancetconstraints.Comparator。</p>
<p>归并排序参数comparator需要实现包constraints.Comparator。</p>
<b>函数签名:</b>
```go
func MergeSort[T any](slice []T, comparator lancetconstraints.Comparator)
func MergeSort[T any](slice []T, comparator constraints.Comparator)
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/ydinn9YzUJn)</span></b>
@@ -394,12 +394,12 @@ func main() {
### <span id="CountSort">CountSort</span>
<p>计数排序参数comparator需要实现包lancetconstraints.Comparator。</p>
<p>计数排序参数comparator需要实现包constraints.Comparator。</p>
<b>函数签名:</b>
```go
func CountSort[T any](slice []T, comparator lancetconstraints.Comparator) []T
func CountSort[T any](slice []T, comparator constraints.Comparator) []T
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/tB-Umgm0DrP)</span></b>
@@ -443,12 +443,12 @@ func main() {
### <span id="BinarySearch">BinarySearch</span>
<p>二分递归查找,返回元素索引,未找到元素返回-1参数comparator需要实现包lancetconstraints.Comparator。</p>
<p>二分递归查找,返回元素索引,未找到元素返回-1参数comparator需要实现包constraints.Comparator。</p>
<b>函数签名:</b>
```go
func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int
func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator constraints.Comparator) int
```
<b>示例: <span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/t6MeGiUSN47)</span></b>
@@ -494,12 +494,12 @@ func main() {
### <span id="BinaryIterativeSearch">BinaryIterativeSearch</span>
<p>二分迭代查找,返回元素索引,未找到元素返回-1参数comparator需要实现包lancetconstraints.Comparator。</p>
<p>二分迭代查找,返回元素索引,未找到元素返回-1参数comparator需要实现包constraints.Comparator。</p>
<b>函数签名:</b>
```go
func BinaryIterativeSearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int
func BinaryIterativeSearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator constraints.Comparator) int
```
<b>示例: <span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/Anozfr8ZLH3)</span></b>

View File

@@ -44,9 +44,9 @@ MaxHeap是通过slice实现的二叉堆树根节点的key既大于等于左
```go
type MaxHeap[T any] struct {
data []T
comparator lancetconstraints.Comparator
comparator constraints.Comparator
}
func NewMaxHeap[T any](comparator lancetconstraints.Comparator) *MaxHeap[T]
func NewMaxHeap[T any](comparator constraints.Comparator) *MaxHeap[T]
```
<b>示例:</b>

View File

@@ -1100,12 +1100,12 @@ func main() {
<b>函数签名:</b>
```go
func NewPriorityQueue[T any](capacity int, comparator lancetconstraints.Comparator) *PriorityQueue[T]
func NewPriorityQueue[T any](capacity int, comparator constraints.Comparator) *PriorityQueue[T]
type PriorityQueue[T any] struct {
items []T
size int
comparator lancetconstraints.Comparator
comparator constraints.Comparator
}
```
<b>示例:</b>

View File

@@ -41,7 +41,7 @@ import (
## 文档
## 1. BSTree
BSTree是一种二叉搜索树数据结构其中每个节点有两个孩子分别称为左孩子和右孩子。 在 BSTree 中leftNode < rootNode < rightNode。 T类型应该实现lancetconstraints.Comparator。
BSTree是一种二叉搜索树数据结构其中每个节点有两个孩子分别称为左孩子和右孩子。 在 BSTree 中leftNode < rootNode < rightNode。 T类型应该实现constraints.Comparator。
### <span id="NewBSTree">NewBSTree</span>
<p>返回BSTree指针实例</p>
@@ -49,11 +49,11 @@ BSTree是一种二叉搜索树数据结构其中每个节点有两个孩子
<b>函数签名:</b>
```go
func NewBSTree[T any](rootData T, comparator lancetconstraints.Comparator) *BSTree[T]
func NewBSTree[T any](rootData T, comparator constraints.Comparator) *BSTree[T]
type BSTree[T any] struct {
root *datastructure.TreeNode[T]
comparator lancetconstraints.Comparator
comparator constraints.Comparator
}
type TreeNode[T any] struct {

View File

@@ -45,6 +45,7 @@ import (
- [Sha](#Sha)
- [ReadCsvFile](#ReadCsvFile)
- [WriteCsvFile](#WriteCsvFile)
- [WriteMapsToCsv](#WriteMapsToCsv)
- [WriteStringToFile](#WriteStringToFile)
- [WriteBytesToFile](#WriteBytesToFile)
- [ReadFile](#ReadFile)
@@ -669,7 +670,7 @@ func main() {
<b>函数签名:</b>
```go
func ReadCsvFile(filepath string) ([][]string, error)
func ReadCsvFile(filepath string, delimiter ...rune) ([][]string, error)
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/OExTkhGEd3_u)</span></b>
@@ -701,7 +702,7 @@ func main() {
<b>函数签名:</b>
```go
func WriteCsvFile(filepath string, records [][]string, append bool) error
func WriteCsvFile(filepath string, records [][]string, append bool, delimiter ...rune) error
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/dAXm58Q5U1o)</span></b>
@@ -743,6 +744,59 @@ func main() {
}
```
### <span id="WriteMapsToCsv">WriteMapsToCsv</span>
<p>将map切片写入csv文件中。</p>
<b>函数签名:</b>
```go
// filepath: CSV文件路径。
// records: 写入文件的map切片。map值必须为基本类型。会以map键的字母顺序写入。
// appendToExistingFile: 是否为追加写模式。
// delimiter: CSV文件分割符。
// headers: CSV文件表头顺序需要与map key保持一致),不指定时按字母排序。
func WriteMapsToCsv(filepath string, records []map[string]any, appendToExistingFile bool, delimiter rune, headers ...[]string) error
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
fpath := "./test.csv"
fileutil.CreateFile(fpath)
f, _ := os.OpenFile(fpath, os.O_WRONLY|os.O_TRUNC, 0777)
defer f.Close()
records := []map[string]any{
{"Name": "Lili", "Age": "22", "Gender": "female"},
{"Name": "Jim", "Age": "21", "Gender": "male"},
}
headers := []string{"Name", "Age", "Gender"}
err := WriteMapsToCsv(csvFilePath, records, false, ';', headers)
if err != nil {
log.Fatal(err)
}
content, err := fileutil.ReadCsvFile(csvFilePath, ';')
fmt.Println(content)
// Output:
// [[Name Age Gender] [Lili 22 female] [Jim 21 male]]
}
```
### <span id="WriteBytesToFile">WriteBytesToFile</span>
<p>将bytes写入文件。</p>

View File

@@ -223,7 +223,7 @@ func main() {
### <span id="RandSymbolChar">RandSymbolChar</span>
<p>生成给定长度的随机符号字符串. 符号字符包括: !@#$%^&*()_+-=[]{}|;':\",./<>?。</p>
<p>生成给定长度的随机符号字符串。</p>
<b>函数签名:</b>
@@ -231,7 +231,7 @@ func main() {
func RandSymbolChar(length int) string
```
<b>示例:</b>
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/Im6ZJxAykOm)</span></b>
```go
package main
@@ -243,7 +243,7 @@ import (
func main() {
randStr := random.RandSymbolChar(6)
fmt.Println(randStr) //@#(_")
fmt.Println(randStr) // 随机特殊字符字符串,例如: @#(_")
}
```
@@ -312,7 +312,7 @@ func main() {
func RandFloat(min, max float64, precision int) float64
```
<b>实例:</b>
<b>实例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/zbD_tuobJtr)</span></b>
```go
package main
@@ -338,7 +338,7 @@ func main() {
func RandFloats(n int, min, max float64, precision int) []float64
```
<b>实例:</b>
<b>实例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/I3yndUQ-rhh)</span></b>
```go
package main

View File

@@ -35,6 +35,7 @@ import (
- [DifferenceBy](#DifferenceBy)
- [DifferenceWith](#DifferenceWith)
- [DeleteAt](#DeleteAt)
- [DeleteRange](#DeleteRange)
- [Drop](#Drop)
- [DropRight](#DropRight)
- [DropWhile](#DropWhile)
@@ -516,12 +517,12 @@ func main() {
### <span id="DeleteAt">DeleteAt</span>
<p>删除切片中指定开始索引到结束索引的元素</p>
<p>删除切片中指定索引的元素(不修改原切片)。</p>
<b>函数签名:</b>
```go
func DeleteAt[T any](slice []T, start int, end ...int)
func DeleteAt[T any](slice []T, index int) []T
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/pJ-d6MUWcvK)</span></b>
@@ -533,18 +534,66 @@ import (
)
func main() {
result1 := slice.DeleteAt([]string{"a", "b", "c"}, -1)
result2 := slice.DeleteAt([]string{"a", "b", "c"}, 0)
result3 := slice.DeleteAt([]string{"a", "b", "c"}, 0, 2)
chars := []string{"a", "b", "c", "d", "e"}
result1 := slice.DeleteAt(chars, 0)
result2 := slice.DeleteAt(chars, 4)
result3 := slice.DeleteAt(chars, 5)
result4 := slice.DeleteAt(chars, 6)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// [a b c]
// [b c]
// [c]
// [b c d e]
// [a b c d]
// [a b c d]
// [a b c d]
}
```
### <span id="DeleteRange">DeleteRange</span>
<p>删除切片中指定索引范围的元素(不修改原切片)。</p>
<b>函数签名:</b>
```go
func DeleteRange[T any](slice []T, start, end int) []T
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
chars := []string{"a", "b", "c", "d", "e"}
result1 := DeleteRange(chars, 0, 0)
result2 := DeleteRange(chars, 0, 1)
result3 := DeleteRange(chars, 0, 3)
result4 := DeleteRange(chars, 0, 4)
result5 := DeleteRange(chars, 0, 5)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
// Output:
// [a b c d e]
// [b c d e]
// [d e]
// [e]
// []
}
```
@@ -2475,18 +2524,18 @@ import (
func main() {
nums := []int{1, 2, 3, 4, 5}
result1 := slice.Partition(nums)
result2 := slice.Partition(nums, func(n int) bool { return n%2 == 0 })
result3 := slice.Partition(nums, func(n int) bool { return n == 1 || n == 2 }, func(n int) bool { return n == 2 || n == 3 || n == 4 })
result1 := slice.Partition(nums)
result2 := slice.Partition(nums, func(n int) bool { return n%2 == 0 })
result3 := slice.Partition(nums, func(n int) bool { return n == 1 || n == 2 }, func(n int) bool { return n == 2 || n == 3 || n == 4 })
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// [[1 2 3 4 5]]
// [[2 4] [1 3 5]]
// [[1 2] [3 4] [5]]
// Output:
// [[1 2 3 4 5]]
// [[2 4] [1 3 5]]
// [[1 2] [3 4] [5]]
}
```
@@ -2501,7 +2550,7 @@ func main() {
func Random[T any](slice []T) (val T, idx int)
```
<b>示例:<span style="float:right;display:inline-block;">[运行](TODO)</span></b>
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/UzpGQptWppw)</span></b>
```go
import (
@@ -2510,13 +2559,13 @@ import (
)
func main() {
nums := []int{1, 2, 3, 4, 5}
nums := []int{1, 2, 3, 4, 5}
val, idx := slice.Random(nums)
if idx >= 0 && idx < len(nums) && slice.Contain(nums, val) {
fmt.Println("okk")
}
// Output:
// okk
val, idx := slice.Random(nums)
if idx >= 0 && idx < len(nums) && slice.Contain(nums, val) {
fmt.Println("okk")
}
// Output:
// okk
}
```

View File

@@ -37,6 +37,7 @@ import (
- [IsExported](#IsExported)
- [IsZero](#IsZero)
- [IsSlice](#IsSlice)
- [IsTargetType](#IsTargetType)
<div STYLE="page-break-after: always;"></div>
@@ -531,4 +532,45 @@ func main() {
// Output:
// true
}
```
### <span id="IsTargetType">IsTargetType</span>
<p>判断属性是否是目标类型</p>
<b>函数签名:</b>
```go
func (f *Field) IsTargetType(targetType reflect.Kind) bool
```
<b>示例:</b>
```go
package main
import (
"fmt"
"reflect"
"github.com/duke-git/lancet/v2/structs"
)
func main() {
type Parent struct {
Name string
arr []int
}
p1 := &Parent{arr: []int{1, 2, 3}}
s := structs.New(p1)
n, _ := s.Field("Name")
a, _ := s.Field("arr")
fmt.Println(n.IsTargetType(reflect.String))
fmt.Println(a.IsTargetType(reflect.Slice))
// Output:
// true
// true
}
```

View File

@@ -43,12 +43,12 @@ import (
### <span id="BubbleSort">BubbleSort</span>
<p>Sort slice with bubble sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
<p>Sort slice with bubble sort algorithm. Param comparator should implements constraints.Comparator.</p>
<b>Signature:</b>
```go
func BubbleSort[T any](slice []T, comparator lancetconstraints.Comparator)
func BubbleSort[T any](slice []T, comparator constraints.Comparator)
```
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/GNdv7Jg2Taj)</span></b>
@@ -91,12 +91,12 @@ func main() {
### <span id="InsertionSort">InsertionSort</span>
<p>Sort slice with insertion sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
<p>Sort slice with insertion sort algorithm. Param comparator should implements constraints.Comparator.</p>
<b>Signature:</b>
```go
func InsertionSort[T any](slice []T, comparator lancetconstraints.Comparator)
func InsertionSort[T any](slice []T, comparator constraints.Comparator)
```
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/G5LJiWgJJW6)</span></b>
@@ -117,7 +117,7 @@ type people struct {
// PeopleAageComparator sort people slice by age field
type peopleAgeComparator struct{}
// Compare implements github.com/duke-git/lancet/lancetconstraints/constraints.go/Comparator
// Compare implements github.com/duke-git/lancet/constraints/constraints.go/Comparator
func (pc *peopleAgeComparator) Compare(v1 any, v2 any) int {
p1, _ := v1.(people)
p2, _ := v2.(people)
@@ -154,12 +154,12 @@ func main() {
### <span id="SelectionSort">SelectionSort</span>
<p>Sort slice with selection sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
<p>Sort slice with selection sort algorithm. Param comparator should implements constraints.Comparator.</p>
<b>Signature:</b>
```go
func SelectionSort[T any](slice []T, comparator lancetconstraints.Comparator)
func SelectionSort[T any](slice []T, comparator constraints.Comparator)
```
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/oXovbkekayS)</span></b>
@@ -202,12 +202,12 @@ func main() {
### <span id="ShellSort">ShellSort</span>
<p>Sort slice with shell sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
<p>Sort slice with shell sort algorithm. Param comparator should implements constraints.Comparator.</p>
<b>Signature:</b>
```go
func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator)
func ShellSort[T any](slice []T, comparator constraints.Comparator)
```
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/3ibkszpJEu3)</span></b>
@@ -250,12 +250,12 @@ func main() {
### <span id="QuickSort">QuickSort</span>
<p>Sort slice with quick sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
<p>Sort slice with quick sort algorithm. Param comparator should implements constraints.Comparator.</p>
<b>Signature:</b>
```go
func QuickSort[T any](slice []T comparator lancetconstraints.Comparator)
func QuickSort[T any](slice []T comparator constraints.Comparator)
```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/7Y7c1Elk3ax)</span></b>
@@ -298,12 +298,12 @@ func main() {
### <span id="HeapSort">HeapSort</span>
<p>Sort slice with heap sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
<p>Sort slice with heap sort algorithm. Param comparator should implements constraints.Comparator.</p>
<b>Signature:</b>
```go
func HeapSort[T any](slice []T, comparator lancetconstraints.Comparator)
func HeapSort[T any](slice []T, comparator constraints.Comparator)
```
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/u6Iwa1VZS_f)</span></b>
@@ -346,12 +346,12 @@ func main() {
### <span id="MergeSort">MergeSort</span>
<p>Sort slice with merge sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
<p>Sort slice with merge sort algorithm. Param comparator should implements constraints.Comparator.</p>
<b>Signature:</b>
```go
func MergeSort[T any](slice []T, comparator lancetconstraints.Comparator)
func MergeSort[T any](slice []T, comparator constraints.Comparator)
```
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/ydinn9YzUJn)</span></b>
@@ -394,12 +394,12 @@ func main() {
### <span id="CountSort">CountSort</span>
<p>Sort slice with count sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
<p>Sort slice with count sort algorithm. Param comparator should implements constraints.Comparator.</p>
<b>Signature:</b>
```go
func CountSort[T any](slice []T, comparator lancetconstraints.Comparator) []T
func CountSort[T any](slice []T, comparator constraints.Comparator) []T
```
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/tB-Umgm0DrP)</span></b>
@@ -448,7 +448,7 @@ func main() {
<b>Signature:</b>
```go
func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int
func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator constraints.Comparator) int
```
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/t6MeGiUSN47)</span></b>
@@ -499,7 +499,7 @@ func main() {
<b>Signature:</b>
```go
func BinaryIterativeSearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int
func BinaryIterativeSearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator constraints.Comparator) int
```
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/Anozfr8ZLH3)</span></b>

View File

@@ -44,9 +44,9 @@ MaxHeap is a binary heap tree implemented by slice, The key of the root node is
```go
type MaxHeap[T any] struct {
data []T
comparator lancetconstraints.Comparator
comparator constraints.Comparator
}
func NewMaxHeap[T any](comparator lancetconstraints.Comparator) *MaxHeap[T]
func NewMaxHeap[T any](comparator constraints.Comparator) *MaxHeap[T]
```
<b>Example:</b>

View File

@@ -1100,12 +1100,12 @@ Common queue implemented by slice.
<b>Signature:</b>
```go
func NewPriorityQueue[T any](capacity int, comparator lancetconstraints.Comparator) *PriorityQueue[T]
func NewPriorityQueue[T any](capacity int, comparator constraints.Comparator) *PriorityQueue[T]
type PriorityQueue[T any] struct {
items []T
size int
comparator lancetconstraints.Comparator
comparator constraints.Comparator
}
```
<b>Example:</b>

View File

@@ -41,7 +41,7 @@ import (
## Documentation
## 1. BSTree
BSTree is a binary search tree data structure in which each node has at two children, which are referred to as the left child and the right child. In BSTree: leftNode < rootNode < rightNode. Type T should implements Compare function in lancetconstraints.Comparator interface.
BSTree is a binary search tree data structure in which each node has at two children, which are referred to as the left child and the right child. In BSTree: leftNode < rootNode < rightNode. Type T should implements Compare function in constraints.Comparator interface.
### <span id="NewBSTree">NewBSTree</span>
<p>Make a BSTree pointer instance</p>
@@ -49,11 +49,11 @@ BSTree is a binary search tree data structure in which each node has at two chil
<b>Signature:</b>
```go
func NewBSTree[T any](rootData T, comparator lancetconstraints.Comparator) *BSTree[T]
func NewBSTree[T any](rootData T, comparator constraints.Comparator) *BSTree[T]
type BSTree[T any] struct {
root *datastructure.TreeNode[T]
comparator lancetconstraints.Comparator
comparator constraints.Comparator
}
type TreeNode[T any] struct {

View File

@@ -45,6 +45,8 @@ import (
- [Sha](#Sha)
- [ReadCsvFile](#ReadCsvFile)
- [WriteCsvFile](#WriteCsvFile)
- [WriteCsvFile](#WriteCsvFile)
- [WriteMapsToCsv](#WriteMapsToCsv)
- [WriteStringToFile](#WriteStringToFile)
- [WriteBytesToFile](#WriteBytesToFile)
- [ReadFile](#ReadFile)
@@ -669,7 +671,7 @@ func main() {
<b>Signature:</b>
```go
func ReadCsvFile(filepath string) ([][]string, error)
func ReadCsvFile(filepath string, delimiter ...rune) ([][]string, error)
```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/OExTkhGEd3_u)</span></b>
@@ -701,7 +703,7 @@ func main() {
<b>Signature:</b>
```go
func WriteCsvFile(filepath string, records [][]string, append bool) error
func WriteCsvFile(filepath string, records [][]string, append bool, delimiter ...rune) error
```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/dAXm58Q5U1o)</span></b>
@@ -743,6 +745,59 @@ func main() {
}
```
### <span id="WriteMapsToCsv">WriteMapsToCsv</span>
<p>Write slice of map to csv file.</p>
<b>Signature:</b>
```go
// filepath: path of the CSV file.
// records: slice of maps to be written. the value of map should be basic type. The maps will be sorted by key in alphabeta order, then be written into csv file.
// appendToExistingFile: If true, data will be appended to the file if it exists.
// delimiter: Delimiter to use in the CSV file.
// headers: order of the csv column headers, needs to be consistent with the key of the map.
func WriteMapsToCsv(filepath string, records []map[string]any, appendToExistingFile bool, delimiter rune, headers ...[]string) error
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
fpath := "./test.csv"
fileutil.CreateFile(fpath)
f, _ := os.OpenFile(fpath, os.O_WRONLY|os.O_TRUNC, 0777)
defer f.Close()
records := []map[string]any{
{"Name": "Lili", "Age": "22", "Gender": "female"},
{"Name": "Jim", "Age": "21", "Gender": "male"},
}
headers := []string{"Name", "Age", "Gender"}
err := fileutil.WriteMapsToCsv(csvFilePath, records, false, ';', headers)
if err != nil {
log.Fatal(err)
}
content, err := fileutil.ReadCsvFile(csvFilePath, ';')
fmt.Println(content)
// Output:
// [[Name Age Gender] [Lili 22 female] [Jim 21 male]]
}
```
### <span id="WriteBytesToFile">WriteBytesToFile</span>
<p>Writes bytes to target file.</p>

View File

@@ -223,7 +223,7 @@ func main() {
### <span id="RandSymbolChar">RandSymbolChar</span>
<p>Generate a random symbol char of specified length. Symbol chars: !@#$%^&*()_+-=[]{}|;':\",./<>?.</p>
<p>Generate a random symbol char of specified length.</p>
<b>Signature:</b>
@@ -231,7 +231,7 @@ func main() {
func RandSymbolChar(length int) string
```
<b>Example:</b>
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/Im6ZJxAykOm)</span></b>
```go
package main
@@ -243,7 +243,7 @@ import (
func main() {
randStr := random.RandSymbolChar(6)
fmt.Println(randStr) //@#(_")
fmt.Println(randStr) // random string like: @#(_")
}
```
@@ -313,7 +313,7 @@ func main() {
func RandFloat(min, max float64, precision int) float64
```
<b>Example:</b>
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/zbD_tuobJtr)</span></b>
```go
package main
@@ -339,7 +339,7 @@ func main() {
func RandFloats(n int, min, max float64, precision int) []float64
```
<b>Example:</b>
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/I3yndUQ-rhh)</span></b>
```go
package main
@@ -351,6 +351,6 @@ import (
func main() {
floatNumbers := random.RandFloats(5, 1.0, 5.0, 2)
fmt.Println(floatNumber) //[3.42 3.99 1.3 2.38 4.23] (random)
fmt.Println(floatNumbers) //[3.42 3.99 1.3 2.38 4.23] (random)
}
```

View File

@@ -35,6 +35,7 @@ import (
- [DifferenceBy](#DifferenceBy)
- [DifferenceWith](#DifferenceWith)
- [DeleteAt](#DeleteAt)
- [DeleteRange](#DeleteRange)
- [Drop](#Drop)
- [DropRight](#DropRight)
- [DropWhile](#DropWhile)
@@ -515,12 +516,12 @@ func main() {
### <span id="DeleteAt">DeleteAt</span>
<p>Delete the element of slice from start index to end index - 1.</p>
<p>Delete delete the element of slice at index.</p>
<b>Signature:</b>
```go
func DeleteAt[T any](slice []T, start int, end ...int)
func DeleteAt[T any](slice []T, index int)
```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/pJ-d6MUWcvK)</span></b>
@@ -532,18 +533,66 @@ import (
)
func main() {
result1 := slice.DeleteAt([]string{"a", "b", "c"}, -1)
result2 := slice.DeleteAt([]string{"a", "b", "c"}, 0)
result3 := slice.DeleteAt([]string{"a", "b", "c"}, 0, 2)
chars := []string{"a", "b", "c", "d", "e"}
result1 := slice.DeleteAt(chars, 0)
result2 := slice.DeleteAt(chars, 4)
result3 := slice.DeleteAt(chars, 5)
result4 := slice.DeleteAt(chars, 6)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// [a b c]
// [b c]
// [c]
// [b c d e]
// [a b c d]
// [a b c d]
// [a b c d]
}
```
### <span id="DeleteRange">DeleteRange</span>
<p>Delete the element of slice from start index to end indexexclude)</p>
<b>Signature:</b>
```go
func DeleteRange[T any](slice []T, start, end int) []T
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
chars := []string{"a", "b", "c", "d", "e"}
result1 := DeleteRange(chars, 0, 0)
result2 := DeleteRange(chars, 0, 1)
result3 := DeleteRange(chars, 0, 3)
result4 := DeleteRange(chars, 0, 4)
result5 := DeleteRange(chars, 0, 5)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
// Output:
// [a b c d e]
// [b c d e]
// [d e]
// [e]
// []
}
```
@@ -2473,18 +2522,18 @@ import (
func main() {
nums := []int{1, 2, 3, 4, 5}
result1 := slice.Partition(nums)
result2 := slice.Partition(nums, func(n int) bool { return n%2 == 0 })
result3 := slice.Partition(nums, func(n int) bool { return n == 1 || n == 2 }, func(n int) bool { return n == 2 || n == 3 || n == 4 })
result1 := slice.Partition(nums)
result2 := slice.Partition(nums, func(n int) bool { return n%2 == 0 })
result3 := slice.Partition(nums, func(n int) bool { return n == 1 || n == 2 }, func(n int) bool { return n == 2 || n == 3 || n == 4 })
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// [[1 2 3 4 5]]
// [[2 4] [1 3 5]]
// [[1 2] [3 4] [5]]
// Output:
// [[1 2 3 4 5]]
// [[2 4] [1 3 5]]
// [[1 2] [3 4] [5]]
}
```
@@ -2498,7 +2547,7 @@ func main() {
func Random[T any](slice []T) (val T, idx int)
```
<b>Example:<span style="float:right;display:inline-block;">[Run](TODO)</span></b>
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/UzpGQptWppw)</span></b>
```go
import (
@@ -2507,13 +2556,13 @@ import (
)
func main() {
nums := []int{1, 2, 3, 4, 5}
nums := []int{1, 2, 3, 4, 5}
val, idx := slice.Random(nums)
if idx >= 0 && idx < len(nums) && slice.Contain(nums, val) {
fmt.Println("okk")
}
// Output:
// okk
val, idx := slice.Random(nums)
if idx >= 0 && idx < len(nums) && slice.Contain(nums, val) {
fmt.Println("okk")
}
// Output:
// okk
}
```

View File

@@ -37,6 +37,7 @@ import (
- [IsExported](#IsExported)
- [IsZero](#IsZero)
- [IsSlice](#IsSlice)
- [IsTargetType](#IsTargetType)
<div STYLE="page-break-after: always;"></div>
@@ -533,3 +534,44 @@ func main() {
// true
}
```
### <span id="IsTargetType">IsTargetType</span>
<p>check if a struct field type is target type or not</p>
<b>Signature:</b>
```go
func (f *Field) IsTargetType(targetType reflect.Kind) bool
```
<b>Example:</b>
```go
package main
import (
"fmt"
"reflect"
"github.com/duke-git/lancet/v2/structs"
)
func main() {
type Parent struct {
Name string
arr []int
}
p1 := &Parent{arr: []int{1, 2, 3}}
s := structs.New(p1)
n, _ := s.Field("Name")
a, _ := s.Field("arr")
fmt.Println(n.IsTargetType(reflect.String))
fmt.Println(a.IsTargetType(reflect.Slice))
// Output:
// true
// true
}
```

View File

@@ -20,11 +20,67 @@ import (
"os"
"path/filepath"
"runtime"
"sort"
"strings"
"github.com/duke-git/lancet/v2/validator"
)
// FileReader is a reader supporting offset seeking and reading one
// line at a time, this is especially useful for large files
type FileReader struct {
*bufio.Reader
file *os.File
offset int64
}
// NewFileReader creates the FileReader struct for reading
func NewFileReader(path string) (*FileReader, error) {
f, err := os.Open(path)
if err != nil {
return nil, err
}
return &FileReader{
file: f,
Reader: bufio.NewReader(f),
offset: 0,
}, nil
}
// ReadLine reads and returns one line at a time excluding the trailing '\r' and '\n'
func (f *FileReader) ReadLine() (string, error) {
data, err := f.Reader.ReadBytes('\n')
f.offset += int64(len(data))
if err == nil || err == io.EOF {
for len(data) > 0 && (data[len(data)-1] == '\r' || data[len(data)-1] == '\n') {
data = data[:len(data)-1]
}
return string(data), err
}
return "", err
}
// Offset returns the current offset of the file
func (f *FileReader) Offset() int64 {
return f.offset
}
// Seek sets the current offset of the reading
func (f *FileReader) Seek(offset int64) error {
_, err := f.file.Seek(offset, 0)
if err != nil {
return err
}
f.Reader = bufio.NewReader(f.file)
f.offset = offset
return nil
}
// Close takes care of the opened file
func (f *FileReader) Close() error {
return f.file.Close()
}
// IsExist checks if a file or directory exists.
// Play: https://go.dev/play/p/nKKXt8ZQbmh
func IsExist(path string) bool {
@@ -508,6 +564,25 @@ func FileSize(path string) (int64, error) {
return f.Size(), nil
}
// DirSize walks the folder recursively and returns folder size in bytes.
func DirSize(path string) (int64, error) {
var size int64
err := filepath.WalkDir(path, func(_ string, d os.DirEntry, err error) error {
if err != nil {
return err
}
if !d.IsDir() {
info, err := d.Info()
if err != nil {
return err
}
size += info.Size()
}
return err
})
return size, err
}
// MTime returns file modified time.
// Play: https://go.dev/play/p/s_Tl7lZoAaY
func MTime(filepath string) (int64, error) {
@@ -536,7 +611,7 @@ func Sha(filepath string, shaType ...int) (string, error) {
} else if shaType[0] == 512 {
h = sha512.New()
} else {
return "", errors.New("param `shaType` should be 1, 256 or 512.")
return "", errors.New("param `shaType` should be 1, 256 or 512")
}
}
@@ -554,15 +629,19 @@ func Sha(filepath string, shaType ...int) (string, error) {
// ReadCsvFile read file content into slice.
// Play: https://go.dev/play/p/OExTkhGEd3_u
func ReadCsvFile(filepath string) ([][]string, error) {
func ReadCsvFile(filepath string, delimiter ...rune) ([][]string, error) {
f, err := os.Open(filepath)
if err != nil {
return nil, err
}
defer f.Close()
csvReader := csv.NewReader(f)
records, err := csvReader.ReadAll()
reader := csv.NewReader(f)
if len(delimiter) > 0 {
reader.Comma = delimiter[0]
}
records, err := reader.ReadAll()
if err != nil {
return nil, err
}
@@ -571,8 +650,10 @@ func ReadCsvFile(filepath string) ([][]string, error) {
}
// WriteCsvFile write content to target csv file.
// append: append to existing csv file
// delimiter: specifies csv delimiter
// Play: https://go.dev/play/p/dAXm58Q5U1o
func WriteCsvFile(filepath string, records [][]string, append bool) error {
func WriteCsvFile(filepath string, records [][]string, append bool, delimiter ...rune) error {
flag := os.O_RDWR | os.O_CREATE
if append {
@@ -587,7 +668,19 @@ func WriteCsvFile(filepath string, records [][]string, append bool) error {
defer f.Close()
writer := csv.NewWriter(f)
writer.Comma = ','
// 设置默认分隔符为逗号,除非另外指定
if len(delimiter) > 0 {
writer.Comma = delimiter[0]
} else {
writer.Comma = ','
}
// 遍历所有记录并处理包含分隔符或双引号的单元格
for i := range records {
for j := range records[i] {
records[i][j] = escapeCSVField(records[i][j], writer.Comma)
}
}
return writer.WriteAll(records)
}
@@ -646,3 +739,71 @@ func ReadFile(path string) (reader io.ReadCloser, closeFn func(), err error) {
return nil, func() {}, errors.New("unknown file type")
}
}
// escapeCSVField 处理单元格内容,如果包含分隔符,则用双引号包裹
func escapeCSVField(field string, delimiter rune) string {
// 替换所有的双引号为两个双引号
escapedField := strings.ReplaceAll(field, "\"", "\"\"")
// 如果字段包含分隔符、双引号或换行符,用双引号包裹整个字段
if strings.ContainsAny(escapedField, string(delimiter)+"\"\n") {
escapedField = fmt.Sprintf("\"%s\"", escapedField)
}
return escapedField
}
// WriteMapsToCsv write slice of map to csv file.
// Play: todo
// filepath: Path to the CSV file.
// records: Slice of maps to be written. the value of map should be basic type.
// the maps will be sorted by key in alphabeta order, then be written into csv file.
// appendToExistingFile: If true, data will be appended to the file if it exists.
// delimiter: Delimiter to use in the CSV file.
// headers: order of the csv column headers, needs to be consistent with the key of the map.
func WriteMapsToCsv(filepath string, records []map[string]any, appendToExistingFile bool, delimiter rune,
headers ...[]string) error {
for _, record := range records {
for _, value := range record {
if !isCsvSupportedType(value) {
return errors.New("unsupported value type detected; only basic types are supported: \nbool, rune, string, int, int64, float32, float64, uint, byte, complex128, complex64, uintptr")
}
}
}
var columnHeaders []string
if len(headers) > 0 {
columnHeaders = headers[0]
} else {
for key := range records[0] {
columnHeaders = append(columnHeaders, key)
}
// sort keys in alphabeta order
sort.Strings(columnHeaders)
}
var datasToWrite [][]string
if !appendToExistingFile {
datasToWrite = append(datasToWrite, columnHeaders)
}
for _, record := range records {
var row []string
for _, h := range columnHeaders {
row = append(row, fmt.Sprintf("%v", record[h]))
}
datasToWrite = append(datasToWrite, row)
}
return WriteCsvFile(filepath, datasToWrite, appendToExistingFile, delimiter)
}
// check if the value of map which to be written into csv is basic type.
func isCsvSupportedType(v interface{}) bool {
switch v.(type) {
case bool, rune, string, int, int64, float32, float64, uint, byte, complex128, complex64, uintptr:
return true
default:
return false
}
}

View File

@@ -3,6 +3,7 @@ package fileutil
import (
"fmt"
"io"
"log"
"os"
)
@@ -331,6 +332,28 @@ func ExampleWriteCsvFile() {
// [[Lili 22 female] [Jim 21 male]]
}
func ExampleWriteMapsToCsv() {
csvFilePath := "./testdata/test3.csv"
records := []map[string]any{
{"Name": "Lili", "Age": "22", "Gender": "female"},
{"Name": "Jim", "Age": "21", "Gender": "male"},
}
headers := []string{"Name", "Age", "Gender"}
err := WriteMapsToCsv(csvFilePath, records, false, ';', headers)
if err != nil {
log.Fatal(err)
}
content, err := ReadCsvFile(csvFilePath, ';')
fmt.Println(content)
// Output:
// [[Name Age Gender] [Lili 22 female] [Jim 21 male]]
}
func ExampleWriteStringToFile() {
filepath := "./test.txt"

View File

@@ -27,7 +27,7 @@ func TestCreateFile(t *testing.T) {
assert := internal.NewAssert(t, "TestCreateFile")
f := "./text.txt"
f := "./testdata/text.txt"
if CreateFile(f) {
file, err := os.Open(f)
assert.IsNil(err)
@@ -340,10 +340,14 @@ func TestSha(t *testing.T) {
assert := internal.NewAssert(t, "TestSha")
sha1, err := Sha("./testdata/test.txt", 1)
sha256, err := Sha("./testdata/test.txt", 256)
sha512, err := Sha("./testdata/test.txt", 512)
assert.IsNil(err)
sha256, err := Sha("./testdata/test.txt", 256)
assert.IsNil(err)
sha512, err := Sha("./testdata/test.txt", 512)
assert.IsNil(err)
assert.Equal("dda3cf10c5a6ff6c6659a497bf7261b287af2bc7", sha1)
assert.Equal("aa6d0a3fbc3442c228d606da09e0c1dc98c69a1cac3da1909199e0266171df35", sha256)
assert.Equal("d22aba2a1b7a2e2f512756255cc1c3708905646920cb1eb95e45b531ba74774dbbb89baebf1f716220eb9cf4908f1cfc5b2a01267704d9a59f59d77cab609870", sha512)
@@ -379,11 +383,36 @@ func TestWriteCsvFile(t *testing.T) {
assert.Equal(2, len(readContent))
assert.Equal(3, len(readContent[0]))
assert.Equal("Lili", content[0][0])
assert.Equal("Lili", readContent[0][0])
// RemoveFile(csvFilePath)
}
func TestWriteMapsToCsv(t *testing.T) {
assert := internal.NewAssert(t, "TestWriteMapsToCSV")
csvFilePath := "./testdata/test4.csv"
records := []map[string]any{
{"Name": "Lili", "Age": "22", "Gender": "female"},
{"Name": "Jim", "Age": "21", "Gender": "male"},
}
headers := []string{"Name", "Age", "Gender"}
err := WriteMapsToCsv(csvFilePath, records, false, ';', headers)
assert.IsNil(err)
content, err := ReadCsvFile(csvFilePath, ';')
assert.IsNil(err)
assert.Equal(3, len(content))
assert.Equal(3, len(content[0]))
assert.Equal("Lili", content[1][0])
assert.Equal("22", content[1][1])
assert.Equal("female", content[1][2])
}
func TestWriteStringToFile(t *testing.T) {
assert := internal.NewAssert(t, "TestWriteStringToFile")
@@ -476,3 +505,42 @@ Disallow: /deny
`
internal.NewAssert(t, "TestReadFile").Equal(want, string(dat))
}
func TestReadlineFile(t *testing.T) {
path := "./testdata/demo.csv"
reader, err := NewFileReader(path)
if err != nil {
t.Fail()
}
defer reader.Close()
indexMap := make(map[string]int64)
defer reader.Close()
for {
offset := reader.Offset()
line, err := reader.ReadLine()
if err == io.EOF {
break
}
indexMap[line] = offset
}
lines, err := ReadFileByLine(path)
if err != nil {
t.Fail()
}
for _, line := range lines {
offset, ok := indexMap[line]
if !ok {
t.Fail()
}
if err = reader.Seek(offset); err != nil {
t.Fail()
}
lineRead, err := reader.ReadLine()
if err == io.EOF {
break
}
internal.NewAssert(t, "TestReadlineFile").Equal(line, lineRead)
}
}

View File

@@ -1,3 +1,5 @@
Lili,22,female
Jim,21,male
1 Lili 22 female
2 Jim 21 male
3
4
5

View File

@@ -1,3 +1,5 @@
Lili,22,female
Jim,21,male
1 Lili 22 female
2 Jim 21 male
3
4
5

3
fileutil/testdata/test3.csv vendored Normal file
View File

@@ -0,0 +1,3 @@
Name;Age;Gender
Lili;22;female
Jim;21;male
1 Name Age Gender
2 Lili 22 female
3 Jim 21 male

3
fileutil/testdata/test4.csv vendored Normal file
View File

@@ -0,0 +1,3 @@
Name;Age;Gender
Lili;22;female
Jim;21;male
1 Name Age Gender
2 Lili 22 female
3 Jim 21 male

View File

@@ -6,12 +6,11 @@ package formatter
import (
"encoding/json"
"fmt"
"io"
"strconv"
"strings"
"github.com/duke-git/lancet/v2/convertor"
"github.com/duke-git/lancet/v2/strutil"
"github.com/duke-git/lancet/v2/validator"
"golang.org/x/exp/constraints"
)
@@ -20,31 +19,24 @@ import (
// 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 {
if validator.IsInt(value) {
v, err := convertor.ToInt(value)
if err != nil {
return ""
}
return symbol + commaInt(v)
}
numString := convertor.ToString(value)
if validator.IsFloat(value) {
v, err := convertor.ToFloat(value)
if err != nil {
return ""
}
return symbol + commaFloat(v)
}
if strutil.IsString(value) {
v := fmt.Sprintf("%v", value)
if validator.IsNumberStr(v) {
return symbol + commaStr(v)
}
_, err := strconv.ParseFloat(numString, 64)
if err != nil {
return ""
}
return ""
index := strings.Index(numString, ".")
if index == -1 {
index = len(numString)
}
for index > 3 {
index = index - 3
numString = numString[:index] + "," + numString[index:]
}
return symbol + numString
}
// Pretty data to JSON string.

View File

@@ -1,85 +0,0 @@
package formatter
import (
"bytes"
"math"
"strconv"
"strings"
)
// see https://github.com/dustin/go-humanize/blob/master/comma.go
func commaInt(v int64) string {
sign := ""
// Min int64 can't be negated to a usable value, so it has to be special cased.
if v == math.MinInt64 {
return "-9,223,372,036,854,775,808"
}
if v < 0 {
sign = "-"
v = 0 - v
}
parts := []string{"", "", "", "", "", "", ""}
j := len(parts) - 1
for v > 999 {
parts[j] = strconv.FormatInt(v%1000, 10)
switch len(parts[j]) {
case 2:
parts[j] = "0" + parts[j]
case 1:
parts[j] = "00" + parts[j]
}
v = v / 1000
j--
}
parts[j] = strconv.Itoa(int(v))
return sign + strings.Join(parts[j:], ",")
}
func commaFloat(v float64) string {
buf := &bytes.Buffer{}
if v < 0 {
buf.Write([]byte{'-'})
v = 0 - v
}
comma := []byte{','}
parts := strings.Split(strconv.FormatFloat(v, 'f', -1, 64), ".")
pos := 0
if len(parts[0])%3 != 0 {
pos += len(parts[0]) % 3
buf.WriteString(parts[0][:pos])
buf.Write(comma)
}
for ; pos < len(parts[0]); pos += 3 {
buf.WriteString(parts[0][pos : pos+3])
buf.Write(comma)
}
buf.Truncate(buf.Len() - 1)
if len(parts) > 1 {
buf.Write([]byte{'.'})
buf.WriteString(parts[1])
}
return buf.String()
}
func commaStr(s string) string {
dotIndex := strings.Index(s, ".")
if dotIndex != -1 {
return commaStrRecursive(s[:dotIndex]) + s[dotIndex:]
}
return commaStrRecursive(s)
}
func commaStrRecursive(s string) string {
if len(s) <= 3 {
return s
}
return commaStrRecursive(s[:len(s)-3]) + "," + commaStrRecursive(s[len(s)-3:])
}

View File

@@ -330,10 +330,10 @@ func Cos(radian float64, precision ...int) float64 {
return TruncRound(radian, 3)
}
// Cos returns the sine of the radian argument.
// Sin returns the sine of the radian argument.
// Play: https://go.dev/play/p/TWMQlMywDsP
func Sin(radian float64, precision ...int) float64 {
return Cos((math.Pi / 2) - radian)
return Cos((math.Pi/2)-radian, precision...)
}
// Log returns the logarithm of base n.

View File

@@ -230,7 +230,6 @@ func UploadFile(filepath string, server string) (bool, error) {
}
// DownloadFile will download the file exist in url to a local file.
// Play: todo
func DownloadFile(filepath string, url string) error {
resp, err := http.Get(url)
if err != nil {

View File

@@ -4,7 +4,9 @@
// Package pointer contains some util functions to operate go pointer.
package pointer
import "reflect"
import (
"reflect"
)
// Of returns a pointer to the value `v`.
// Play: https://go.dev/play/p/HFd70x4DrMj
@@ -47,5 +49,10 @@ func ExtractPointer(value any) any {
if t.Kind() != reflect.Pointer {
return value
}
return ExtractPointer(v.Elem().Interface())
if v.Elem().IsValid() {
return ExtractPointer(v.Elem().Interface())
}
return nil
}

View File

@@ -8,20 +8,25 @@ import (
crand "crypto/rand"
"fmt"
"io"
"math"
"math/rand"
"time"
"unsafe"
"github.com/duke-git/lancet/v2/mathutil"
)
const (
Numeral = "0123456789"
LowwerLetters = "abcdefghijklmnopqrstuvwxyz"
UpperLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
Letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
SymbolChars = "!@#$%^&*()_+-=[]{}|;':\",./<>?"
MaximumCapacity = 1 << 31
Numeral = "0123456789"
LowwerLetters = "abcdefghijklmnopqrstuvwxyz"
UpperLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
Letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
SymbolChars = "!@#$%^&*()_+-=[]{}|;':\",./<>?"
)
var rn = rand.NewSource(time.Now().UnixNano())
func init() {
rand.Seed(time.Now().UnixNano())
}
@@ -41,7 +46,7 @@ func RandInt(min, max int) int {
}
// RandFloat generate random float64 number between [min, max) with specific precision.
// Play: todo
// Play: https://go.dev/play/p/zbD_tuobJtr
func RandFloat(min, max float64, precision int) float64 {
if min == max {
return min
@@ -103,23 +108,66 @@ func RandNumeralOrLetter(length int) string {
// RandSymbolChar generate a random symbol char of specified length.
// symbol chars: !@#$%^&*()_+-=[]{}|;':\",./<>?.
// Play: todo
// Play: https://go.dev/play/p/Im6ZJxAykOm
func RandSymbolChar(length int) string {
return random(SymbolChars, length)
}
// nearestPowerOfTwo 返回一个大于等于cap的最近的2的整数次幂参考java8的hashmap的tableSizeFor函数
func nearestPowerOfTwo(cap int) int {
n := cap - 1
n |= n >> 1
n |= n >> 2
n |= n >> 4
n |= n >> 8
n |= n >> 16
if n < 0 {
return 1
} else if n >= MaximumCapacity {
return MaximumCapacity
}
return n + 1
}
// random generate a random string based on given string range.
func random(s string, length int) string {
b := make([]byte, length)
// fix: https://github.com/duke-git/lancet/issues/75
// r := rand.New(rand.NewSource(time.Now().UnixNano()))
for i := range b {
b[i] = s[rand.Int63()%int64(len(s))]
// 仿照strings.Builder
// 创建一个长度为 length 的字节切片
bytes := make([]byte, length)
strLength := len(s)
if strLength <= 0 {
return ""
} else if strLength == 1 {
for i := 0; i < length; i++ {
bytes[i] = s[0]
}
return *(*string)(unsafe.Pointer(&bytes))
}
return string(b)
// s的字符需要使用多少个比特位数才能表示完
// letterIdBits := int(math.Ceil(math.Log2(strLength))),下面比上面的代码快
letterIdBits := int(math.Log2(float64(nearestPowerOfTwo(strLength))))
// 最大的字母id掩码
var letterIdMask int64 = 1<<letterIdBits - 1
// 可用次数的最大值
letterIdMax := 63 / letterIdBits
// 循环生成随机字符串
for i, cache, remain := length-1, rn.Int63(), letterIdMax; i >= 0; {
// 检查随机数生成器是否用尽所有随机数
if remain == 0 {
cache, remain = rn.Int63(), letterIdMax
}
// 从可用字符的字符串中随机选择一个字符
if idx := int(cache & letterIdMask); idx < len(s) {
bytes[i] = s[idx]
i--
}
// 右移比特位数,为下次选择字符做准备
cache >>= letterIdBits
remain--
}
// 仿照strings.Builder用unsafe包返回一个字符串避免拷贝
// 将字节切片转换为字符串并返回
return *(*string)(unsafe.Pointer(&bytes))
}
// UUIdV4 generate a random UUID of version 4 according to RFC 4122.
@@ -164,7 +212,7 @@ func RandUniqueIntSlice(n, min, max int) []int {
}
// RandFloats generate a slice of random float64 numbers of length n that do not repeat.
// Play: todo
// Play: https://go.dev/play/p/I3yndUQ-rhh
func RandFloats(n int, min, max float64, precision int) []float64 {
nums := make([]float64, n)
used := make(map[float64]struct{}, n)

View File

@@ -498,20 +498,13 @@ func FlatMap[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
accumulator := initial
for i, v := range slice {
accumulator = iteratee(i, v, accumulator)
}
result := iteratee(0, initial, slice[0])
tmp := make([]T, 2)
for i := 1; i < len(slice); i++ {
tmp[0] = result
tmp[1] = slice[i]
result = iteratee(i, tmp[0], tmp[1])
}
return result
return accumulator
}
// ReduceBy produces a value from slice by accumulating the result of each element as passed through the reducer function.
@@ -625,35 +618,34 @@ func IntSlice(slice any) []int {
return result
}
// DeleteAt delete the element of slice from start index to end index - 1.
// DeleteAt delete the element of slice at index.
// Play: https://go.dev/play/p/pJ-d6MUWcvK
func DeleteAt[T any](slice []T, start int, end ...int) []T {
size := len(slice)
if start < 0 || start >= size {
return slice
func DeleteAt[T any](slice []T, index int) []T {
if index >= len(slice) {
index = len(slice) - 1
}
if len(end) > 0 {
end := end[0]
if end <= start {
return slice
}
if end > size {
end = size
}
result := make([]T, len(slice)-1)
copy(result, slice[:index])
copy(result[index:], slice[index+1:])
slice = append(slice[:start], slice[end:]...)
return slice
return result
}
// DeleteRange delete the element of slice from start index to end indexexclude).
// Play: todo
func DeleteRange[T any](slice []T, start, end int) []T {
result := make([]T, 0, len(slice)-(end-start))
for i := 0; i < start; i++ {
result = append(result, slice[i])
}
if start == size-1 {
slice = slice[:start]
} else {
slice = append(slice[:start], slice[start+1:]...)
for i := end; i < len(slice); i++ {
result = append(result, slice[i])
}
return slice
return result
}
// Drop drop n elements from the start of a slice.
@@ -1232,7 +1224,7 @@ func Partition[T any](slice []T, predicates ...func(item T) bool) [][]T {
}
// Random get a random item of slice, return idx=-1 when slice is empty
// Play: todo
// Play: https://go.dev/play/p/UzpGQptWppw
func Random[T any](slice []T) (val T, idx int) {
if len(slice) == 0 {
return val, -1

View File

@@ -594,18 +594,46 @@ func ExampleIntSlice() {
}
func ExampleDeleteAt() {
result1 := DeleteAt([]string{"a", "b", "c"}, -1)
result2 := DeleteAt([]string{"a", "b", "c"}, 0)
result3 := DeleteAt([]string{"a", "b", "c"}, 0, 2)
chars := []string{"a", "b", "c", "d", "e"}
result1 := DeleteAt(chars, 0)
result2 := DeleteAt(chars, 4)
result3 := DeleteAt(chars, 5)
result4 := DeleteAt(chars, 6)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// [a b c]
// [b c]
// [c]
// [b c d e]
// [a b c d]
// [a b c d]
// [a b c d]
}
func ExampleDeleteRange() {
chars := []string{"a", "b", "c", "d", "e"}
result1 := DeleteRange(chars, 0, 0)
result2 := DeleteRange(chars, 0, 1)
result3 := DeleteRange(chars, 0, 3)
result4 := DeleteRange(chars, 0, 4)
result5 := DeleteRange(chars, 0, 5)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
// Output:
// [a b c d e]
// [b c d e]
// [d e]
// [e]
// []
}
func ExampleDrop() {

View File

@@ -572,19 +572,27 @@ func TestDeleteAt(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDeleteAt")
arr := []int{1, 2, 3, 4, 5}
assert.Equal([]string{"a", "b", "c"}, DeleteAt([]string{"a", "b", "c"}, -1))
assert.Equal([]string{"a", "b", "c"}, DeleteAt([]string{"a", "b", "c"}, 3))
assert.Equal([]string{"b", "c"}, DeleteAt([]string{"a", "b", "c"}, 0))
assert.Equal([]string{"a", "c"}, DeleteAt([]string{"a", "b", "c"}, 1))
assert.Equal([]string{"a", "b"}, DeleteAt([]string{"a", "b", "c"}, 2))
assert.Equal([]int{2, 3, 4, 5}, DeleteAt(arr, 0))
assert.Equal([]int{1, 2, 3, 4}, DeleteAt(arr, 4))
assert.Equal([]string{"b", "c"}, DeleteAt([]string{"a", "b", "c"}, 0, 1))
assert.Equal([]string{"c"}, DeleteAt([]string{"a", "b", "c"}, 0, 2))
assert.Equal([]string{}, DeleteAt([]string{"a", "b", "c"}, 0, 3))
assert.Equal([]string{}, DeleteAt([]string{"a", "b", "c"}, 0, 4))
assert.Equal([]string{"a"}, DeleteAt([]string{"a", "b", "c"}, 1, 3))
assert.Equal([]string{"a"}, DeleteAt([]string{"a", "b", "c"}, 1, 4))
assert.Equal([]int{1, 2, 3, 4}, DeleteAt(arr, 5))
assert.Equal([]int{1, 2, 3, 4}, DeleteAt(arr, 6))
assert.Equal([]int{1, 2, 3, 4, 5}, arr)
}
func TestDeleteRange(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDeleteRange")
arr := []int{1, 2, 3, 4, 5}
assert.Equal([]int{1, 2, 3, 4, 5}, DeleteRange(arr, 0, 0))
assert.Equal([]int{2, 3, 4, 5}, DeleteRange(arr, 0, 1))
assert.Equal([]int{4, 5}, DeleteRange(arr, 0, 3))
}
func TestDrop(t *testing.T) {

View File

@@ -52,6 +52,16 @@ func (f *Field) IsZero() bool {
return reflect.DeepEqual(z, v)
}
// IsNil returns true if the given field is nil value.
func (f *Field) IsNil() bool {
v := f.Value()
if v == nil || (reflect.ValueOf(v)).Kind() == reflect.Ptr && reflect.ValueOf(v).IsNil() {
return true
}
return false
}
// Name returns the name of the given field
func (f *Field) Name() string {
return f.field.Name
@@ -68,6 +78,11 @@ func (f *Field) IsSlice() bool {
return k == reflect.Slice
}
// IsTargetType check if a struct field type is target type or not
func (f *Field) IsTargetType(targetType reflect.Kind) bool {
return f.rvalue.Kind() == targetType
}
// mapValue covert field value to map
func (f *Field) mapValue(value any) any {
val := pointer.ExtractPointer(value)
@@ -106,7 +121,9 @@ func (f *Field) mapValue(value any) any {
ret = v.Interface()
}
default:
ret = v.Interface()
if v.Kind().String() != "invalid" {
ret = v.Interface()
}
}
return ret
}

View File

@@ -154,6 +154,25 @@ func TestField_IsSlice(t *testing.T) {
assert.Equal(true, a.IsSlice())
}
func TestField_IsTargetType(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestField_IsTargetType")
type Parent struct {
Name string
arr []int
}
p1 := &Parent{Name: "test", arr: []int{1, 2, 3}}
s := New(p1)
n, _ := s.Field("Name")
a, _ := s.Field("arr")
assert.Equal(true, n.IsTargetType(reflect.String))
assert.Equal(true, a.IsTargetType(reflect.Slice))
}
func TestField_MapValue(t *testing.T) {
t.Parallel()

View File

@@ -2,6 +2,7 @@
package structs
import (
"fmt"
"reflect"
"github.com/duke-git/lancet/v2/pointer"
@@ -61,7 +62,7 @@ func New(value any, tagName ...string) *Struct {
// ToMap convert the exported fields of a struct to map.
func (s *Struct) ToMap() (map[string]any, error) {
if !s.IsStruct() {
return nil, errInvalidStruct(s)
return nil, fmt.Errorf("invalid struct %v", s)
}
result := make(map[string]any)
@@ -70,9 +71,15 @@ func (s *Struct) ToMap() (map[string]any, error) {
if !f.IsExported() || f.tag.IsEmpty() || f.tag.Name == "-" {
continue
}
if f.IsZero() && f.tag.HasOption("omitempty") {
continue
}
if f.IsNil() {
continue
}
result[f.tag.Name] = f.mapValue(f.Value())
}

View File

@@ -1,7 +0,0 @@
package structs
import "fmt"
func errInvalidStruct(v any) error {
return fmt.Errorf("invalid struct %v", v)
}

View File

@@ -65,6 +65,45 @@ func TestStruct_ToMap(t *testing.T) {
})
}
func Test_ToMap2(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestStruct_ToMap")
type M struct {
Name string `json:"name"`
}
type S struct {
ID int `json:"id"`
M *M `json:"m"`
}
s1 := &S{
ID: 1,
}
var expect1 = map[string]any{"id": 1}
map1, err := ToMap(s1)
assert.IsNil(err)
assert.Equal(expect1, map1)
s2 := &S{
ID: 1,
M: &M{
Name: "test",
},
}
var expect2 = map[string]any{
"id": 1,
"m": map[string]any{
"name": "test",
}}
map2, err := ToMap(s2)
assert.IsNil(err)
assert.Equal(expect2, map2)
}
func TestStruct_Fields(t *testing.T) {
t.Parallel()

View File

@@ -4,7 +4,6 @@
package strutil
import (
"reflect"
"regexp"
"strings"
"unicode"
@@ -380,10 +379,7 @@ func RemoveNonPrintable(str string) string {
// StringToBytes converts a string to byte slice without a memory allocation.
// Play: https://go.dev/play/p/7OyFBrf9AxA
func StringToBytes(str string) (b []byte) {
sh := *(*reflect.StringHeader)(unsafe.Pointer(&str))
bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
bh.Data, bh.Len, bh.Cap = sh.Data, sh.Len, sh.Len
return b
return *(*[]byte)(unsafe.Pointer(&str))
}
// BytesToString converts a byte slice to string without a memory allocation.

View File

@@ -14,12 +14,6 @@ func TestTryUnwrap(t *testing.T) {
assert := internal.NewAssert(t, "TestTryUnwrap")
assert.Equal(42, TryUnwrap(strconv.Atoi("42")))
}
func TestTryUnwrapFail(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestTryUnwrapFail")
_, err := strconv.Atoi("4o2")
defer func() {
@@ -76,8 +70,6 @@ func TestXError_Unwrap(t *testing.T) {
}
func TestXError_StackTrace(t *testing.T) {
// t.Parallel()
assert := internal.NewAssert(t, "TestXError_StackTrace")
err := New("error")
@@ -86,7 +78,7 @@ func TestXError_StackTrace(t *testing.T) {
assert.Equal(3, len(stacks))
assert.Equal("github.com/duke-git/lancet/v2/xerror.TestXError_StackTrace", stacks[0].Func)
assert.Equal(83, stacks[0].Line)
assert.Equal(75, stacks[0].Line)
assert.Equal(true, strings.Contains(stacks[0].File, "xerror_test.go"))
}