mirror of
https://github.com/duke-git/lancet.git
synced 2026-03-01 00:35:28 +08:00
Compare commits
5 Commits
a06bb8ee6a
...
be62aaac9b
| Author | SHA1 | Date | |
|---|---|---|---|
| be62aaac9b | |||
| e0c9ccbce3 | |||
| d2d1e5a055 | |||
| bbc58c7e46 | |||
| ac2ecceaec |
@@ -706,6 +706,8 @@ import "github.com/duke-git/lancet/v2/fileutil"
|
|||||||
[[play](https://go.dev/play/p/OExTkhGEd3_u)]
|
[[play](https://go.dev/play/p/OExTkhGEd3_u)]
|
||||||
- **<big>WriteCsvFile</big>** : write content to target csv file.
|
- **<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)]
|
[[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)]
|
[[play](https://go.dev/play/p/dAXm58Q5U1o)]
|
||||||
- **<big>WriteBytesToFile</big>** : write bytes to target file.
|
- **<big>WriteBytesToFile</big>** : write bytes to target file.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/fileutil.md#WriteBytesToFile)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/fileutil.md#WriteBytesToFile)]
|
||||||
@@ -1178,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.
|
- **<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)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#DifferenceWith)]
|
||||||
[[play](https://go.dev/play/p/v2U2deugKuV)]
|
[[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)]
|
[[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 index(exclude).
|
||||||
|
[[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.
|
- **<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)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#Drop)]
|
||||||
[[play](https://go.dev/play/p/jnPO2yQsT8H)]
|
[[play](https://go.dev/play/p/jnPO2yQsT8H)]
|
||||||
|
|||||||
+6
-3
@@ -705,8 +705,10 @@ import "github.com/duke-git/lancet/v2/fileutil"
|
|||||||
- **<big>ReadCsvFile</big>** : 读取 csv 文件内容到切片。
|
- **<big>ReadCsvFile</big>** : 读取 csv 文件内容到切片。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/fileutil.md#ReadCsvFile)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/fileutil.md#ReadCsvFile)]
|
||||||
[[play](https://go.dev/play/p/OExTkhGEd3_u)]
|
[[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)]
|
[[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)]
|
[[play](https://go.dev/play/p/dAXm58Q5U1o)]
|
||||||
- **<big>WriteBytesToFile</big>** : 将 bytes 写入文件。
|
- **<big>WriteBytesToFile</big>** : 将 bytes 写入文件。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/fileutil.md#WriteBytesToFile)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/fileutil.md#WriteBytesToFile)]
|
||||||
@@ -1177,9 +1179,10 @@ import "github.com/duke-git/lancet/v2/slice"
|
|||||||
- **<big>DifferenceWith</big>** : 接受比较器函数,该比较器被调用以将切片的元素与值进行比较。 结果值的顺序和引用由第一个切片确定。
|
- **<big>DifferenceWith</big>** : 接受比较器函数,该比较器被调用以将切片的元素与值进行比较。 结果值的顺序和引用由第一个切片确定。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#DifferenceWith)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#DifferenceWith)]
|
||||||
[[play](https://go.dev/play/p/v2U2deugKuV)]
|
[[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)]
|
[[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 个元素。
|
- **<big>Drop</big>** : 从切片头部删除 n 个元素。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#Drop)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#Drop)]
|
||||||
[[play](https://go.dev/play/p/jnPO2yQsT8H)]
|
[[play](https://go.dev/play/p/jnPO2yQsT8H)]
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ import (
|
|||||||
- [Sha](#Sha)
|
- [Sha](#Sha)
|
||||||
- [ReadCsvFile](#ReadCsvFile)
|
- [ReadCsvFile](#ReadCsvFile)
|
||||||
- [WriteCsvFile](#WriteCsvFile)
|
- [WriteCsvFile](#WriteCsvFile)
|
||||||
|
- [WriteMapsToCsv](#WriteMapsToCsv)
|
||||||
- [WriteStringToFile](#WriteStringToFile)
|
- [WriteStringToFile](#WriteStringToFile)
|
||||||
- [WriteBytesToFile](#WriteBytesToFile)
|
- [WriteBytesToFile](#WriteBytesToFile)
|
||||||
- [ReadFile](#ReadFile)
|
- [ReadFile](#ReadFile)
|
||||||
@@ -750,7 +751,12 @@ func main() {
|
|||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func WriteMapsToCsv(filepath string, records []map[string]string, append_to_existing_file bool, delimiter ...rune) error
|
// 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>
|
<b>示例:</b>
|
||||||
@@ -770,23 +776,24 @@ func main() {
|
|||||||
f, _ := os.OpenFile(fpath, os.O_WRONLY|os.O_TRUNC, 0777)
|
f, _ := os.OpenFile(fpath, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
records := []map[string]string{
|
records := []map[string]any{
|
||||||
{"Name": "Lili", "Age": "22", "gender": "female"},
|
{"Name": "Lili", "Age": "22", "Gender": "female"},
|
||||||
{"Name": "Jim", "Age": "21", "gender": "male"},
|
{"Name": "Jim", "Age": "21", "Gender": "male"},
|
||||||
}
|
}
|
||||||
|
|
||||||
err := WriteMapsToCsv(csvFilePath, records, false, ';')
|
headers := []string{"Name", "Age", "Gender"}
|
||||||
|
err := WriteMapsToCsv(csvFilePath, records, false, ';', headers)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
content, err := ReadCsvFile(csvFilePath, ';')
|
content, err := fileutil.ReadCsvFile(csvFilePath, ';')
|
||||||
|
|
||||||
fmt.Println(content)
|
fmt.Println(content)
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// [[Name Age gender] [Lili 22 female] [Jim 21 male]]
|
// [[Name Age Gender] [Lili 22 female] [Jim 21 male]]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import (
|
|||||||
- [DifferenceBy](#DifferenceBy)
|
- [DifferenceBy](#DifferenceBy)
|
||||||
- [DifferenceWith](#DifferenceWith)
|
- [DifferenceWith](#DifferenceWith)
|
||||||
- [DeleteAt](#DeleteAt)
|
- [DeleteAt](#DeleteAt)
|
||||||
|
- [DeleteRange](#DeleteRange)
|
||||||
- [Drop](#Drop)
|
- [Drop](#Drop)
|
||||||
- [DropRight](#DropRight)
|
- [DropRight](#DropRight)
|
||||||
- [DropWhile](#DropWhile)
|
- [DropWhile](#DropWhile)
|
||||||
@@ -516,12 +517,12 @@ func main() {
|
|||||||
|
|
||||||
### <span id="DeleteAt">DeleteAt</span>
|
### <span id="DeleteAt">DeleteAt</span>
|
||||||
|
|
||||||
<p>删除切片中指定开始索引到结束索引的元素</p>
|
<p>删除切片中指定索引的元素(不修改原切片)。</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```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>
|
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/pJ-d6MUWcvK)</span></b>
|
||||||
@@ -533,18 +534,66 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
result1 := slice.DeleteAt([]string{"a", "b", "c"}, -1)
|
chars := []string{"a", "b", "c", "d", "e"}
|
||||||
result2 := slice.DeleteAt([]string{"a", "b", "c"}, 0)
|
|
||||||
result3 := slice.DeleteAt([]string{"a", "b", "c"}, 0, 2)
|
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(result1)
|
||||||
fmt.Println(result2)
|
fmt.Println(result2)
|
||||||
fmt.Println(result3)
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// [a b c]
|
// [b c d e]
|
||||||
// [b c]
|
// [a b c d]
|
||||||
// [c]
|
// [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]
|
||||||
|
// []
|
||||||
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ import (
|
|||||||
- [Sha](#Sha)
|
- [Sha](#Sha)
|
||||||
- [ReadCsvFile](#ReadCsvFile)
|
- [ReadCsvFile](#ReadCsvFile)
|
||||||
- [WriteCsvFile](#WriteCsvFile)
|
- [WriteCsvFile](#WriteCsvFile)
|
||||||
|
- [WriteCsvFile](#WriteCsvFile)
|
||||||
- [WriteMapsToCsv](#WriteMapsToCsv)
|
- [WriteMapsToCsv](#WriteMapsToCsv)
|
||||||
- [WriteStringToFile](#WriteStringToFile)
|
- [WriteStringToFile](#WriteStringToFile)
|
||||||
- [WriteBytesToFile](#WriteBytesToFile)
|
- [WriteBytesToFile](#WriteBytesToFile)
|
||||||
@@ -751,7 +752,12 @@ func main() {
|
|||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func WriteMapsToCsv(filepath string, records []map[string]string, append_to_existing_file bool, delimiter ...rune) error
|
// 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>
|
<b>Example:</b>
|
||||||
@@ -771,23 +777,24 @@ func main() {
|
|||||||
f, _ := os.OpenFile(fpath, os.O_WRONLY|os.O_TRUNC, 0777)
|
f, _ := os.OpenFile(fpath, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
records := []map[string]string{
|
records := []map[string]any{
|
||||||
{"Name": "Lili", "Age": "22", "gender": "female"},
|
{"Name": "Lili", "Age": "22", "Gender": "female"},
|
||||||
{"Name": "Jim", "Age": "21", "gender": "male"},
|
{"Name": "Jim", "Age": "21", "Gender": "male"},
|
||||||
}
|
}
|
||||||
|
|
||||||
err := WriteMapsToCsv(csvFilePath, records, false, ';')
|
headers := []string{"Name", "Age", "Gender"}
|
||||||
|
err := fileutil.WriteMapsToCsv(csvFilePath, records, false, ';', headers)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
content, err := ReadCsvFile(csvFilePath, ';')
|
content, err := fileutil.ReadCsvFile(csvFilePath, ';')
|
||||||
|
|
||||||
fmt.Println(content)
|
fmt.Println(content)
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// [[Name Age gender] [Lili 22 female] [Jim 21 male]]
|
// [[Name Age Gender] [Lili 22 female] [Jim 21 male]]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import (
|
|||||||
- [DifferenceBy](#DifferenceBy)
|
- [DifferenceBy](#DifferenceBy)
|
||||||
- [DifferenceWith](#DifferenceWith)
|
- [DifferenceWith](#DifferenceWith)
|
||||||
- [DeleteAt](#DeleteAt)
|
- [DeleteAt](#DeleteAt)
|
||||||
|
- [DeleteRange](#DeleteRange)
|
||||||
- [Drop](#Drop)
|
- [Drop](#Drop)
|
||||||
- [DropRight](#DropRight)
|
- [DropRight](#DropRight)
|
||||||
- [DropWhile](#DropWhile)
|
- [DropWhile](#DropWhile)
|
||||||
@@ -515,12 +516,12 @@ func main() {
|
|||||||
|
|
||||||
### <span id="DeleteAt">DeleteAt</span>
|
### <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>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```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>
|
<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() {
|
func main() {
|
||||||
result1 := slice.DeleteAt([]string{"a", "b", "c"}, -1)
|
chars := []string{"a", "b", "c", "d", "e"}
|
||||||
result2 := slice.DeleteAt([]string{"a", "b", "c"}, 0)
|
|
||||||
result3 := slice.DeleteAt([]string{"a", "b", "c"}, 0, 2)
|
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(result1)
|
||||||
fmt.Println(result2)
|
fmt.Println(result2)
|
||||||
fmt.Println(result3)
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// [a b c]
|
// [b c d e]
|
||||||
// [b c]
|
// [a b c d]
|
||||||
// [c]
|
// [a b c d]
|
||||||
|
// [a b c d]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="DeleteRange">DeleteRange</span>
|
||||||
|
|
||||||
|
<p>Delete the element of slice from start index to end index(exclude)</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]
|
||||||
|
// []
|
||||||
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
+44
-21
@@ -20,6 +20,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/duke-git/lancet/v2/validator"
|
"github.com/duke-git/lancet/v2/validator"
|
||||||
@@ -754,33 +755,55 @@ func escapeCSVField(field string, delimiter rune) string {
|
|||||||
|
|
||||||
// WriteMapsToCsv write slice of map to csv file.
|
// WriteMapsToCsv write slice of map to csv file.
|
||||||
// Play: todo
|
// Play: todo
|
||||||
func WriteMapsToCsv(filepath string, records []map[string]string, append_to_existing_file bool, delimiter ...rune) error {
|
// filepath: Path to the CSV file.
|
||||||
var datas_to_write [][]string
|
// 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.
|
||||||
var headers []string
|
// appendToExistingFile: If true, data will be appended to the file if it exists.
|
||||||
if len(records) > 0 {
|
// 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] {
|
for key := range records[0] {
|
||||||
headers = append(headers, key)
|
columnHeaders = append(columnHeaders, key)
|
||||||
}
|
}
|
||||||
|
// sort keys in alphabeta order
|
||||||
|
sort.Strings(columnHeaders)
|
||||||
}
|
}
|
||||||
// 追加模式不重复写字段名
|
|
||||||
if !append_to_existing_file {
|
var datasToWrite [][]string
|
||||||
datas_to_write = append(datas_to_write, headers)
|
if !appendToExistingFile {
|
||||||
|
datasToWrite = append(datasToWrite, columnHeaders)
|
||||||
}
|
}
|
||||||
// 写入数据行
|
|
||||||
for _, record := range records {
|
for _, record := range records {
|
||||||
var row []string
|
var row []string
|
||||||
for _, header := range headers {
|
for _, h := range columnHeaders {
|
||||||
row = append(row, record[header])
|
row = append(row, fmt.Sprintf("%v", record[h]))
|
||||||
}
|
}
|
||||||
datas_to_write = append(datas_to_write, row)
|
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
|
||||||
}
|
}
|
||||||
// 提取自定义分隔符
|
|
||||||
var sep rune
|
|
||||||
if len(delimiter) > 0 {
|
|
||||||
sep = delimiter[0]
|
|
||||||
} else {
|
|
||||||
sep = ','
|
|
||||||
}
|
|
||||||
return WriteCsvFile(filepath, datas_to_write, append_to_existing_file, sep)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package fileutil
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"log"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -331,26 +332,27 @@ func ExampleWriteCsvFile() {
|
|||||||
// [[Lili 22 female] [Jim 21 male]]
|
// [[Lili 22 female] [Jim 21 male]]
|
||||||
}
|
}
|
||||||
|
|
||||||
// func ExampleWriteMapsToCsv() {
|
func ExampleWriteMapsToCsv() {
|
||||||
// csvFilePath := "./testdata/test3.csv"
|
csvFilePath := "./testdata/test3.csv"
|
||||||
// records := []map[string]string{
|
records := []map[string]any{
|
||||||
// {"Name": "Lili", "Age": "22", "gender": "female"},
|
{"Name": "Lili", "Age": "22", "Gender": "female"},
|
||||||
// {"Name": "Jim", "Age": "21", "gender": "male"},
|
{"Name": "Jim", "Age": "21", "Gender": "male"},
|
||||||
// }
|
}
|
||||||
|
|
||||||
// err := WriteMapsToCsv(csvFilePath, records, false, ';')
|
headers := []string{"Name", "Age", "Gender"}
|
||||||
|
err := WriteMapsToCsv(csvFilePath, records, false, ';', headers)
|
||||||
|
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// log.Fatal(err)
|
log.Fatal(err)
|
||||||
// }
|
}
|
||||||
|
|
||||||
// content, err := ReadCsvFile(csvFilePath, ';')
|
content, err := ReadCsvFile(csvFilePath, ';')
|
||||||
|
|
||||||
// fmt.Println(content) //顺序不固定
|
fmt.Println(content)
|
||||||
|
|
||||||
// // Output:
|
// Output:
|
||||||
// // [[Name Age gender] [Lili 22 female] [Jim 21 male]]
|
// [[Name Age Gender] [Lili 22 female] [Jim 21 male]]
|
||||||
// }
|
}
|
||||||
|
|
||||||
func ExampleWriteStringToFile() {
|
func ExampleWriteStringToFile() {
|
||||||
filepath := "./test.txt"
|
filepath := "./test.txt"
|
||||||
|
|||||||
@@ -392,12 +392,13 @@ func TestWriteMapsToCsv(t *testing.T) {
|
|||||||
assert := internal.NewAssert(t, "TestWriteMapsToCSV")
|
assert := internal.NewAssert(t, "TestWriteMapsToCSV")
|
||||||
|
|
||||||
csvFilePath := "./testdata/test4.csv"
|
csvFilePath := "./testdata/test4.csv"
|
||||||
records := []map[string]string{
|
records := []map[string]any{
|
||||||
{"Name": "Lili", "Age": "22", "gender": "female"},
|
{"Name": "Lili", "Age": "22", "Gender": "female"},
|
||||||
{"Name": "Jim", "Age": "21", "gender": "male"},
|
{"Name": "Jim", "Age": "21", "Gender": "male"},
|
||||||
}
|
}
|
||||||
|
|
||||||
err := WriteMapsToCsv(csvFilePath, records, false, ';')
|
headers := []string{"Name", "Age", "Gender"}
|
||||||
|
err := WriteMapsToCsv(csvFilePath, records, false, ';', headers)
|
||||||
|
|
||||||
assert.IsNil(err)
|
assert.IsNil(err)
|
||||||
|
|
||||||
@@ -407,7 +408,9 @@ func TestWriteMapsToCsv(t *testing.T) {
|
|||||||
|
|
||||||
assert.Equal(3, len(content))
|
assert.Equal(3, len(content))
|
||||||
assert.Equal(3, len(content[0]))
|
assert.Equal(3, len(content[0]))
|
||||||
// assert.Equal("Lili", content[1][0])
|
assert.Equal("Lili", content[1][0])
|
||||||
|
assert.Equal("22", content[1][1])
|
||||||
|
assert.Equal("female", content[1][2])
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWriteStringToFile(t *testing.T) {
|
func TestWriteStringToFile(t *testing.T) {
|
||||||
|
|||||||
Vendored
+3
-3
@@ -1,3 +1,3 @@
|
|||||||
Age;gender;Name
|
Name;Age;Gender
|
||||||
22;female;Lili
|
Lili;22;female
|
||||||
21;male;Jim
|
Jim;21;male
|
||||||
|
|||||||
|
Vendored
+1
-1
@@ -1,3 +1,3 @@
|
|||||||
Name;Age;gender
|
Name;Age;Gender
|
||||||
Lili;22;female
|
Lili;22;female
|
||||||
Jim;21;male
|
Jim;21;male
|
||||||
|
|||||||
|
Vendored
+26
-34
@@ -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.
|
// Reduce creates an slice of values by running each element of slice thru iteratee function.
|
||||||
// Play: https://go.dev/play/p/_RfXJJWIsIm
|
// Play: https://go.dev/play/p/_RfXJJWIsIm
|
||||||
func Reduce[T any](slice []T, iteratee func(index int, item1, item2 T) T, initial T) T {
|
func Reduce[T any](slice []T, iteratee func(index int, item1, item2 T) T, initial T) T {
|
||||||
if len(slice) == 0 {
|
accumulator := initial
|
||||||
return initial
|
|
||||||
|
for i, v := range slice {
|
||||||
|
accumulator = iteratee(i, v, accumulator)
|
||||||
}
|
}
|
||||||
|
|
||||||
result := iteratee(0, initial, slice[0])
|
return accumulator
|
||||||
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReduceBy produces a value from slice by accumulating the result of each element as passed through the reducer function.
|
// 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
|
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
|
// Play: https://go.dev/play/p/pJ-d6MUWcvK
|
||||||
func DeleteAt[T any](slice []T, start int, end ...int) []T {
|
func DeleteAt[T any](slice []T, index int) []T {
|
||||||
size := len(slice)
|
if index >= len(slice) {
|
||||||
|
index = len(slice) - 1
|
||||||
if start < 0 || start >= size {
|
|
||||||
return slice
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(end) > 0 {
|
result := make([]T, len(slice)-1)
|
||||||
end := end[0]
|
copy(result, slice[:index])
|
||||||
if end <= start {
|
copy(result[index:], slice[index+1:])
|
||||||
return slice
|
|
||||||
}
|
return result
|
||||||
if end > size {
|
}
|
||||||
end = size
|
|
||||||
|
// DeleteRange delete the element of slice from start index to end index(exclude).
|
||||||
|
// 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])
|
||||||
}
|
}
|
||||||
|
|
||||||
slice = append(slice[:start], slice[end:]...)
|
for i := end; i < len(slice); i++ {
|
||||||
return slice
|
result = append(result, slice[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
if start == size-1 {
|
return result
|
||||||
slice = slice[:start]
|
|
||||||
} else {
|
|
||||||
slice = append(slice[:start], slice[start+1:]...)
|
|
||||||
}
|
|
||||||
|
|
||||||
return slice
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Drop drop n elements from the start of a slice.
|
// Drop drop n elements from the start of a slice.
|
||||||
|
|||||||
@@ -594,18 +594,46 @@ func ExampleIntSlice() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ExampleDeleteAt() {
|
func ExampleDeleteAt() {
|
||||||
result1 := DeleteAt([]string{"a", "b", "c"}, -1)
|
chars := []string{"a", "b", "c", "d", "e"}
|
||||||
result2 := DeleteAt([]string{"a", "b", "c"}, 0)
|
|
||||||
result3 := DeleteAt([]string{"a", "b", "c"}, 0, 2)
|
result1 := DeleteAt(chars, 0)
|
||||||
|
result2 := DeleteAt(chars, 4)
|
||||||
|
result3 := DeleteAt(chars, 5)
|
||||||
|
result4 := DeleteAt(chars, 6)
|
||||||
|
|
||||||
fmt.Println(result1)
|
fmt.Println(result1)
|
||||||
fmt.Println(result2)
|
fmt.Println(result2)
|
||||||
fmt.Println(result3)
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// [a b c]
|
// [b c d e]
|
||||||
// [b c]
|
// [a b c d]
|
||||||
// [c]
|
// [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() {
|
func ExampleDrop() {
|
||||||
|
|||||||
+19
-11
@@ -572,19 +572,27 @@ func TestDeleteAt(t *testing.T) {
|
|||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
assert := internal.NewAssert(t, "TestDeleteAt")
|
assert := internal.NewAssert(t, "TestDeleteAt")
|
||||||
|
arr := []int{1, 2, 3, 4, 5}
|
||||||
|
|
||||||
assert.Equal([]string{"a", "b", "c"}, DeleteAt([]string{"a", "b", "c"}, -1))
|
assert.Equal([]int{2, 3, 4, 5}, DeleteAt(arr, 0))
|
||||||
assert.Equal([]string{"a", "b", "c"}, DeleteAt([]string{"a", "b", "c"}, 3))
|
assert.Equal([]int{1, 2, 3, 4}, DeleteAt(arr, 4))
|
||||||
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([]string{"b", "c"}, DeleteAt([]string{"a", "b", "c"}, 0, 1))
|
assert.Equal([]int{1, 2, 3, 4}, DeleteAt(arr, 5))
|
||||||
assert.Equal([]string{"c"}, DeleteAt([]string{"a", "b", "c"}, 0, 2))
|
assert.Equal([]int{1, 2, 3, 4}, DeleteAt(arr, 6))
|
||||||
assert.Equal([]string{}, DeleteAt([]string{"a", "b", "c"}, 0, 3))
|
|
||||||
assert.Equal([]string{}, DeleteAt([]string{"a", "b", "c"}, 0, 4))
|
assert.Equal([]int{1, 2, 3, 4, 5}, arr)
|
||||||
assert.Equal([]string{"a"}, DeleteAt([]string{"a", "b", "c"}, 1, 3))
|
}
|
||||||
assert.Equal([]string{"a"}, DeleteAt([]string{"a", "b", "c"}, 1, 4))
|
|
||||||
|
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) {
|
func TestDrop(t *testing.T) {
|
||||||
|
|||||||
Reference in New Issue
Block a user