1
0
mirror of https://github.com/duke-git/lancet.git synced 2026-02-23 13:52:26 +08:00

Compare commits

...

30 Commits

Author SHA1 Message Date
dudaodong
4eeeabb227 feat: add Delete method for hashmap 2022-08-23 15:07:54 +08:00
dudaodong
b3437fdddf feat: add Delete method for hashmap 2022-08-23 15:07:13 +08:00
dudaodong
312dcab369 feat: add Delete method for hashmap 2022-08-23 15:05:32 +08:00
dudaodong
0cb89f4f46 test: add unit test for HashMap 2022-08-23 14:15:51 +08:00
dudaodong
a2dec87995 feat: add Put method for hashmap 2022-08-23 14:11:14 +08:00
dudaodong
9094cb29bf feat: add new HashMap data structure 2022-08-22 15:21:30 +08:00
dudaodong
ddb992ad2f refactor: BuildMaxHeap 2022-08-22 11:10:17 +08:00
dudaodong
24f18aaaec refactor: change function sign for QuickSort 2022-08-22 11:02:25 +08:00
dudaodong
36169874e5 refactor: change sort file name 2022-08-22 10:58:47 +08:00
dudaodong
23aeb6ac99 refactor: change sort file name 2022-08-22 10:57:04 +08:00
dudaodong
a1984f0a59 feat: add BuildMaxHeap 2022-08-22 10:51:37 +08:00
IceCafeCup
c95db23d2c feat: Set struct uses empty struct as value (#55) 2022-08-13 12:39:30 +08:00
Abirdcfly
fbf251d805 delete minor unreachable code caused by log.Fatal (#54)
Signed-off-by: Abirdcfly <fp544037857@gmail.com>
2022-08-10 14:19:21 +08:00
dudaodong
337f08a04b fix: issue #53 2022-08-06 17:41:45 +08:00
dudaodong
c6a7371049 change lastest v1 version 2022-08-03 10:02:46 +08:00
dudaodong
b697858038 release v2.1.4 2022-08-03 09:56:02 +08:00
dudaodong
5446f7e33c doc: add document for list methods 2022-07-28 12:56:11 +08:00
dudaodong
553f63e76b refactor: update param name in AppendIfAbsent 2022-07-27 15:45:34 +08:00
dudaodong
fc3e94df58 doc: add document for AppendIfAbsent function 2022-07-27 15:44:54 +08:00
dudaodong
5c66f38a5b test: fix test function name TestAppendIfAbsent 2022-07-27 15:38:51 +08:00
郑一诺她爸
70e213b3f7 feat:(slice add AppendIfAbsent function) (#52)
Co-authored-by: george.zheng <george.zheng@ambergroup.io>
2022-07-25 20:52:33 +08:00
donutloop
c1b7500bcb List: add cap (#51)
Cap return cap of the inner data
2022-07-25 20:50:31 +08:00
donutloop
3d7600a9e4 list: add DeleteIf method (#50)
DeleteIf delete all satisfying f(data[i]), returns count of removed elements
2022-07-23 18:52:29 +08:00
donutloop
0299c454ab list: add sublist method (#49)
SubList returns a sub list of the original list between the specified fromIndex, inclusive, and toIndex, exclusive.
2022-07-23 15:00:04 +08:00
dudaodong
741af66404 test: add todo fix for TestSchedule 2022-07-22 10:30:44 +08:00
dudaodong
ef5d0379a1 doc: fix missing word 2022-07-22 10:24:34 +08:00
dudaodong
105ab49763 refactor: change slice Contain logic, convert to map first, then check existence 2022-07-22 10:22:34 +08:00
dudaodong
b5ba9ba573 fix: fix TestMapToSlice function result independent of order of elements 2022-07-22 10:17:23 +08:00
donutloop
ac3baac5c6 list: Add LastIndexOfFunc and IndexOfFunc method (#48)
* LastIndexOfFunc returns the index of the last occurrence of the value in this list satisfying f(data[i])
* IndexOfFunc returns the first index satisfying f(v)
2022-07-22 10:04:31 +08:00
donutloop
a82b5dd206 list: add LastIndexOf (#46)
Add LastIndexOf method too List and fix doc

LastIndexOf returns the index of the last occurrence of the value in this list.
if not found return -1
2022-07-21 15:19:18 +08:00
23 changed files with 832 additions and 50 deletions

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.1.3-green.svg)](https://github.com/duke-git/lancet/releases)
[![Release](https://img.shields.io/badge/release-2.1.4-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)
@@ -35,9 +35,9 @@ English | [简体中文](./README_zh-CN.md)
go get github.com/duke-git/lancet/v2 // will install latest version of v2.x.x
```
2. <b>For users who use version below go1.18, you should install v1.x.x. now latest v1 is v1.3.0. </b>
2. <b>For users who use version below go1.18, you should install v1.x.x. now latest v1 is v1.3.1. </b>
```go
go get github.com/duke-git/lancet@v1.3.0 // below go1.18, install latest version of v1.x.x
go get github.com/duke-git/lancet@v1.3.1 // below go1.18, install latest version of v1.x.x
```
## Usage
@@ -371,6 +371,7 @@ import "github.com/duke-git/lancet/v2/slice"
```
#### Function list:
- [AppendIfAbsent](https://github.com/duke-git/lancet/blob/main/docs/slice.md#AppendIfAbsent)
- [Contain](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Contain)
- [ContainSubSlice](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ContainSubSlice)
- [Chunk](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Chunk)

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.1.3-green.svg)](https://github.com/duke-git/lancet/releases)
[![Release](https://img.shields.io/badge/release-2.1.4-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)
@@ -35,9 +35,9 @@
go get github.com/duke-git/lancet/v2 //安装v2最新版本v2.x.x
```
2. <b>使用go1.18以下版本的用户必须安装v1.x.x。目前最新的v1版本是v1.3.0。</b>
2. <b>使用go1.18以下版本的用户必须安装v1.x.x。目前最新的v1版本是v1.3.1。</b>
```go
go get github.com/duke-git/lancet@v1.3.0 // 使用go1.18以下版本, 必须安装v1.x.x版本
go get github.com/duke-git/lancet@v1.3.1 // 使用go1.18以下版本, 必须安装v1.x.x版本
```
## 用法
@@ -367,6 +367,7 @@ import "github.com/duke-git/lancet/v2/slice"
```
#### 函数列表:
- [AppendIfAbsent](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#AppendIfAbsent)
- [Contain](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Contain)
- [ContainSubSlice](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ContainSubSlice)
- [Chunk](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Chunk)
@@ -488,7 +489,6 @@ import "github.com/duke-git/lancet/v2/validator"
- [IsUrl](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsUrl)
- [IsWeakPassword](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsWeakPassword)
validator.md#IsWeakPassword)
### 19. xerror包实现一些错误处理函数
```go

View File

@@ -65,11 +65,15 @@ func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator) {
}
// QuickSort quick sorting for slice, lowIndex is 0 and highIndex is len(slice)-1
func QuickSort[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) {
func QuickSort[T any](slice []T, comparator lancetconstraints.Comparator) {
quickSort(slice, 0, len(slice)-1, comparator)
}
func quickSort[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) {
if lowIndex < highIndex {
p := partition(slice, lowIndex, highIndex, comparator)
QuickSort(slice, lowIndex, p-1, comparator)
QuickSort(slice, p+1, highIndex, comparator)
quickSort(slice, lowIndex, p-1, comparator)
quickSort(slice, p+1, highIndex, comparator)
}
}

View File

@@ -30,14 +30,6 @@ func (pc *peopleAgeComparator) Compare(v1 any, v2 any) int {
return 0
}
// var peoples = []people{
// {Name: "a", Age: 20},
// {Name: "b", Age: 10},
// {Name: "c", Age: 17},
// {Name: "d", Age: 8},
// {Name: "e", Age: 28},
// }
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
@@ -53,8 +45,6 @@ func (c *intComparator) Compare(v1 any, v2 any) int {
return 0
}
// var intSlice = []int{2, 1, 5, 3, 6, 4}
func TestBubbleSortForStructSlice(t *testing.T) {
asssert := internal.NewAssert(t, "TestBubbleSortForStructSlice")
@@ -151,7 +141,7 @@ func TestQuickSort(t *testing.T) {
{Name: "e", Age: 28},
}
comparator := &peopleAgeComparator{}
QuickSort(peoples, 0, len(peoples)-1, comparator)
QuickSort(peoples, comparator)
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
actual := fmt.Sprintf("%v", peoples)

View File

@@ -6,6 +6,7 @@ import (
"testing"
"github.com/duke-git/lancet/v2/internal"
"github.com/duke-git/lancet/v2/slice"
)
func TestToChar(t *testing.T) {
@@ -204,7 +205,10 @@ func TestMapToSlice(t *testing.T) {
return key + ":" + strconv.Itoa(value)
})
assert.Equal([]string{"a:1", "b:2", "c:3"}, result)
assert.Equal(3, len(result))
assert.Equal(true, slice.Contain(result, "a:1"))
assert.Equal(true, slice.Contain(result, "b:2"))
assert.Equal(true, slice.Contain(result, "c:3"))
}
func TestColorHexToRGB(t *testing.T) {

View File

@@ -0,0 +1,136 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package datastructure implements some data structure. eg. list, linklist, stack, queue, tree, graph.
package datastructure
import (
"fmt"
"hash/fnv"
)
var defaultMapCapacity uint64 = 1 << 10
type mapNode struct {
key any
value any
next *mapNode
}
//HashMap implements a hash map
type HashMap struct {
capacity uint64
size uint64
table []*mapNode
}
// NewHashMap return a HashMap instance
func NewHashMap() *HashMap {
return &HashMap{
capacity: defaultMapCapacity,
table: make([]*mapNode, defaultMapCapacity),
}
}
// NewHashMapWithCapacity return a HashMap instance with given size and capacity
func NewHashMapWithCapacity(size, capacity uint64) *HashMap {
return &HashMap{
size: size,
capacity: capacity,
table: make([]*mapNode, capacity),
}
}
// Get return the value of given key in hashmap
func (hm *HashMap) Get(key any) any {
hashValue := hm.hash(key)
node := hm.table[hashValue]
if node != nil {
return node.value
}
return nil
}
// Put new key value in hashmap
func (hm *HashMap) Put(key any, value any) any {
return hm.putValue(hm.hash(key), key, value)
}
func (hm *HashMap) putValue(hash uint64, key, value any) any {
if hm.capacity == 0 {
hm.capacity = defaultMapCapacity
hm.table = make([]*mapNode, defaultMapCapacity)
}
node := hm.table[hash]
if node == nil {
hm.table[hash] = newMapNode(key, value)
} else if node.key == key {
hm.table[hash] = newMapNodeWithNext(key, value, node)
return value
} else {
hm.resize()
return hm.putValue(hash, value, value)
}
hm.size++
return value
}
// Delete item by given key in hashmap
func (hm *HashMap) Delete(key any) {
hash := hm.hash(key)
node := hm.table[hash]
if node == nil {
return
}
hm.table = append(hm.table[:hash], hm.table[hash+1:]...)
hm.size--
}
// Contains checks if given key is in hashmap or not
func (hm *HashMap) Contains(key any) bool {
node := hm.table[hm.hash(key)]
return node != nil
}
func (hm *HashMap) resize() {
hm.capacity <<= 1
tempTable := hm.table
for i := 0; i < len(tempTable); i++ {
node := tempTable[i]
if node == nil {
continue
}
hm.table[hm.hash(node.key)] = node
}
}
func (hm *HashMap) hash(key any) uint64 {
h := fnv.New64a()
_, _ = h.Write([]byte(fmt.Sprintf("%v", key)))
hashValue := h.Sum64()
return (hm.capacity - 1) & (hashValue ^ (hashValue >> 16))
}
func newMapNode(key, value any) *mapNode {
return &mapNode{
key: key,
value: value,
}
}
func newMapNodeWithNext(key, value any, next *mapNode) *mapNode {
return &mapNode{
key: key,
value: value,
next: next,
}
}

View File

@@ -0,0 +1,42 @@
package datastructure
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
)
func TestHashMap_PutAndGet(t *testing.T) {
assert := internal.NewAssert(t, "TestHashMap_PutAndGet")
hm := NewHashMap()
hm.Put("abc", 3)
assert.Equal(3, hm.Get("abc"))
assert.IsNil(hm.Get("abcd"))
hm.Put("abc", 4)
assert.Equal(4, hm.Get("abc"))
}
func TestHashMap_Delete(t *testing.T) {
assert := internal.NewAssert(t, "TestHashMap_Delete")
hm := NewHashMap()
hm.Put("abc", 3)
assert.Equal(3, hm.Get("abc"))
hm.Delete("abc")
assert.IsNil(hm.Get("abc"))
}
func TestHashMap_Contains(t *testing.T) {
assert := internal.NewAssert(t, "TestHashMap_Contains")
hm := NewHashMap()
assert.Equal(false, hm.Contains("abc"))
hm.Put("abc", 3)
assert.Equal(true, hm.Contains("abc"))
}

View File

@@ -25,6 +25,20 @@ 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] {
heap := &MaxHeap[T]{
data: make([]T, 0, len(data)),
comparator: comparator,
}
for _, v := range data {
heap.Push(v)
}
return heap
}
// Push value into the heap
func (h *MaxHeap[T]) Push(value T) {
h.data = append(h.data, value)

View File

@@ -20,6 +20,20 @@ func (c *intComparator) Compare(v1, v2 any) int {
return 0
}
func TestMaxHeap_BuildMaxHeap(t *testing.T) {
assert := internal.NewAssert(t, "TestMaxHeap_BuildMaxHeap")
values := []int{6, 5, 2, 4, 7, 10, 12, 1, 3, 8, 9, 11}
heap := BuildMaxHeap(values, &intComparator{})
expected := []int{12, 9, 11, 4, 8, 10, 7, 1, 3, 5, 6, 2}
assert.Equal(expected, heap.data)
assert.Equal(12, heap.Size())
heap.PrintStructure()
}
func TestMaxHeap_Push(t *testing.T) {
assert := internal.NewAssert(t, "TestMaxHeap_Push")

View File

@@ -31,7 +31,7 @@ func (l *List[T]) ValueOf(index int) (*T, bool) {
return &l.data[index], true
}
// IndexOf reture the index of value. if not found return -1
// IndexOf returns the index of value. if not found return -1
func (l *List[T]) IndexOf(value T) int {
index := -1
data := l.data
@@ -44,6 +44,48 @@ func (l *List[T]) IndexOf(value T) int {
return index
}
// LastIndexOf returns the index of the last occurrence of the value in this list.
// if not found return -1
func (l *List[T]) LastIndexOf(value T) int {
index := -1
data := l.data
for i := len(data) - 1; i >= 0; i-- {
if reflect.DeepEqual(data[i], value) {
index = i
break
}
}
return index
}
// IndexOfFunc returns the first index satisfying f(v)
// if not found return -1
func (l *List[T]) IndexOfFunc(f func(T) bool) int {
index := -1
data := l.data
for i, v := range data {
if f(v) {
index = i
break
}
}
return index
}
// LastIndexOfFunc returns the index of the last occurrence of the value in this list satisfying f(data[i])
// if not found return -1
func (l *List[T]) LastIndexOfFunc(f func(T) bool) int {
index := -1
data := l.data
for i := len(data) - 1; i >= 0; i-- {
if f(data[i]) {
index = i
break
}
}
return index
}
// Contain checks if the value in the list or not
func (l *List[T]) Contain(value T) bool {
data := l.data
@@ -121,6 +163,31 @@ func (l *List[T]) DeleteAt(index int) {
l.data = data
}
// DeleteIf delete all satisfying f(data[i]), returns count of removed elements
func (l *List[T]) DeleteIf(f func(T) bool) int {
data := l.data
size := len(data)
var c int
for index := 0; index < len(data); index++ {
if !f(data[index]) {
continue
}
if index == size-1 {
data = append(data[:index])
} else {
data = append(data[:index], data[index+1:]...)
index--
}
c++
}
if c > 0 {
l.data = data
}
return c
}
// UpdateAt update value of list at index, index shoud between 0 and list size -1
func (l *List[T]) UpdateAt(index int, value T) {
data := l.data
@@ -181,6 +248,11 @@ func (l *List[T]) Size() int {
return len(l.data)
}
// Cap return cap of the inner data
func (l *List[T]) Cap() int {
return cap(l.data)
}
// Swap the value of index i and j in list
func (l *List[T]) Swap(i, j int) {
size := len(l.data)
@@ -243,3 +315,11 @@ func (l *List[T]) Intersection(other *List[T]) *List[T] {
return result
}
// SubList returns a sub list of the original list between the specified fromIndex, inclusive, and toIndex, exclusive.
func (l *List[T]) SubList(fromIndex, toIndex int) *List[T] {
data := l.data[fromIndex:toIndex]
subList := make([]T, len(data))
copy(subList, data)
return NewList(subList)
}

View File

@@ -36,6 +36,51 @@ func TestIndexOf(t *testing.T) {
assert.Equal(-1, i)
}
func TestIndexOfFunc(t *testing.T) {
assert := internal.NewAssert(t, "TestIndexOf")
list := NewList([]int{1, 2, 3})
i := list.IndexOfFunc(func(a int) bool { return a == 1 })
assert.Equal(0, i)
i = list.IndexOfFunc(func(a int) bool { return a == 4 })
assert.Equal(-1, i)
}
func TestLastIndexOf(t *testing.T) {
assert := internal.NewAssert(t, "TestIndexOf")
list := NewList([]int{1, 2, 3, 3, 3, 3, 4, 5, 6, 9})
i := list.LastIndexOf(3)
assert.Equal(5, i)
i = list.LastIndexOf(10)
assert.Equal(-1, i)
i = list.LastIndexOf(4)
assert.Equal(6, i)
i = list.LastIndexOf(1)
assert.Equal(0, i)
}
func TestLastIndexOfFunc(t *testing.T) {
assert := internal.NewAssert(t, "TestIndexOf")
list := NewList([]int{1, 2, 3, 3, 3, 3, 4, 5, 6, 9})
i := list.LastIndexOfFunc(func(a int) bool { return a == 3 })
assert.Equal(5, i)
i = list.LastIndexOfFunc(func(a int) bool { return a == 10 })
assert.Equal(-1, i)
i = list.LastIndexOfFunc(func(a int) bool { return a == 4 })
assert.Equal(6, i)
i = list.LastIndexOfFunc(func(a int) bool { return a == 1 })
assert.Equal(0, i)
}
func TestContain(t *testing.T) {
assert := internal.NewAssert(t, "TestContain")
@@ -216,6 +261,18 @@ func TestSize(t *testing.T) {
assert.Equal(0, empty.Size())
}
func TestCap(t *testing.T) {
assert := internal.NewAssert(t, "TestCap")
data := make([]int, 0, 100)
list := NewList(data)
assert.Equal(100, list.Cap())
data = make([]int, 0)
list = NewList(data)
assert.Equal(0, list.Cap())
}
func TestSwap(t *testing.T) {
assert := internal.NewAssert(t, "TestSwap")
@@ -270,3 +327,33 @@ func TestIntersection(t *testing.T) {
list3 := list1.Intersection(list2)
assert.Equal(true, expected.Equal(list3))
}
func TestSubSlice(t *testing.T) {
assert := internal.NewAssert(t, "TestSubSlice")
list := NewList([]int{1, 2, 3, 4, 5, 8})
subList := list.SubList(2, 5)
assert.Equal([]int{3, 4, 5}, subList.Data())
}
func BenchmarkSubSlice(b *testing.B) {
list := NewList([]int{1, 2, 3, 4, 5, 8})
for n := 0; n < b.N; n++ {
list.SubList(2, 5)
}
}
func TestDeleteIf(t *testing.T) {
assert := internal.NewAssert(t, "TestDeleteIf")
list := NewList([]int{1, 1, 1, 1, 2, 3, 1, 1, 4, 1, 1, 1, 1, 1, 1})
count := list.DeleteIf(func(a int) bool { return a == 1 })
assert.Equal([]int{2, 3, 4}, list.Data())
assert.Equal(12, count)
count = list.DeleteIf(func(a int) bool { return a == 5 })
assert.Equal([]int{2, 3, 4}, list.Data())
assert.Equal(0, count)
}

View File

@@ -1,7 +1,7 @@
package datastructure
// Set is a data container, like slice, but element of set is not duplicate
type Set[T comparable] map[T]bool
type Set[T comparable] map[T]struct{}
// NewSet return a instance of set
func NewSet[T comparable](values ...T) Set[T] {
@@ -13,7 +13,7 @@ func NewSet[T comparable](values ...T) Set[T] {
// Add value to set
func (s Set[T]) Add(values ...T) {
for _, v := range values {
s[v] = true
s[v] = struct{}{}
}
}

View File

@@ -5,7 +5,7 @@ Package algorithm implements some basic algorithm. eg. sort, search.
## Source
- [https://github.com/duke-git/lancet/blob/main/algorithm/sorter.go](https://github.com/duke-git/lancet/blob/main/algorithm/sorter.go)
- [https://github.com/duke-git/lancet/blob/main/algorithm/sort.go](https://github.com/duke-git/lancet/blob/main/algorithm/sort.go)
- [https://github.com/duke-git/lancet/blob/main/algorithm/search.go](https://github.com/duke-git/lancet/blob/main/algorithm/search.go)
- [https://github.com/duke-git/lancet/blob/main/algorithm/lru_cache.go](https://github.com/duke-git/lancet/blob/main/algorithm/lru_cache.go)
@@ -248,7 +248,7 @@ func main() {
<b>Signature:</b>
```go
func QuickSort[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraints.Comparator)
func QuickSort[T any](slice []T comparator lancetconstraints.Comparator)
```
<b>Example:</b>
@@ -278,7 +278,7 @@ func main() {
intSlice := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
algorithm.QuickSort(intSlice, 0, len(intSlice)-1, comparator)
algorithm.QuickSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
}

View File

@@ -5,7 +5,7 @@ algorithm算法包实现一些基本算法sortsearchlrucache。
## 源码
- [https://github.com/duke-git/lancet/blob/main/algorithm/sorter.go](https://github.com/duke-git/lancet/blob/main/algorithm/sorter.go)
- [https://github.com/duke-git/lancet/blob/main/algorithm/sort.go](https://github.com/duke-git/lancet/blob/main/algorithm/sort.go)
- [https://github.com/duke-git/lancet/blob/main/algorithm/search.go](https://github.com/duke-git/lancet/blob/main/algorithm/search.go)
- [https://github.com/duke-git/lancet/blob/main/algorithm/lru_cache.go](https://github.com/duke-git/lancet/blob/main/algorithm/lru_cache.go)
@@ -249,7 +249,7 @@ func main() {
<b>函数签名:</b>
```go
func QuickSort[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) []T
func QuickSort[T any](slice []T, comparator lancetconstraints.Comparator) []T
```
<b>Example:</b>
@@ -279,7 +279,7 @@ func main() {
intSlice := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
algorithm.QuickSort(intSlice, 0, len(intSlice)-1, comparator)
algorithm.QuickSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
}

View File

@@ -26,6 +26,9 @@ import (
- [Data](#Data)
- [ValueOf](#ValueOf)
- [IndexOf](#IndexOf)
- [LastIndexOf](#LastIndexOf)
- [IndexOfFunc](#IndexOfFunc)
- [LastIndexOfFunc](#LastIndexOfFunc)
- [Push](#Push)
- [PopFirst](#PopFirst)
- [PopLast](#PopLast)
@@ -38,11 +41,14 @@ import (
- [Clone](#Clone)
- [Merge](#Merge)
- [Size](#Size)
- [Cap](#Cap)
- [Swap](#Swap)
- [Reverse](#Reverse)
- [Unique](#Unique)
- [Union](#Union)
- [Intersection](#Intersection)
- [SubList](#SubList)
- [DeleteIf](#DeleteIf)
<div STYLE="page-break-after: always;"></div>
@@ -167,7 +173,7 @@ func main() {
### <span id="IndexOf">IndexOf</span>
<p>Reture the index of value in the list. if not found return -1</p>
<p>Returns the index of value in the list. if not found return -1</p>
<b>Signature:</b>
@@ -192,6 +198,84 @@ func main() {
}
```
### <span id="LastIndexOf">LastIndexOf</span>
<p> Returns the index of the last occurrence of the value in this list if not found return -1</p>
<b>Signature:</b>
```go
func (l *List[T]) LastIndexOf(value T) int
```
<b>Example:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
li := list.NewList([]int{1, 2, 3, 1})
fmt.Println(li.LastIndexOf(1)) // 3
fmt.Println(li.LastIndexOf(0)) //-1
}
```
### <span id="IndexOfFunc">IndexOfFunc</span>
<p> IndexOfFunc returns the first index satisfying f(v). if not found return -1</p>
<b>Signature:</b>
```go
func (l *List[T]) IndexOfFunc(f func(T) bool) int
```
<b>Example:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
li := list.NewList([]int{1, 2, 3})
fmt.Println(li.IndexOfFunc(func(a int) bool { return a == 1 })) //0
fmt.Println(li.IndexOfFunc(func(a int) bool { return a == 0 })) //-1
}
```
### <span id="LastIndexOfFunc">LastIndexOfFunc</span>
<p>LastIndexOfFunc returns the index of the last occurrence of the value in this list satisfying f(data[i]). if not found return -1</p>
<b>Signature:</b>
```go
func (l *List[T]) LastIndexOfFunc(f func(T) bool) int
```
<b>Example:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
li := list.NewList([]int{1, 2, 3, 1})
fmt.Println(li.LastIndexOfFunc(func(a int) bool { return a == 1 })) // 3
fmt.Println(li.LastIndexOfFunc(func(a int) bool { return a == 0 })) //-1
}
```
### <span id="Push">Push</span>
@@ -568,6 +652,36 @@ func main() {
### <span id="Cap">Cap</span>
<p>Cap return cap of the inner data</p>
<b>Signature:</b>
```go
func (l *List[T]) Cap() int
```
<b>Example:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
data := make([]int, 0, 100)
li := list.NewList(data)
fmt.Println(li.Cap()) // 100
}
```
### <span id="Swap">Swap</span>
<p>Swap the value at two index in list</p>
@@ -710,4 +824,61 @@ func main() {
fmt.Println(li3.Data()) //4
}
```
```
### <span id="SubList">SubList</span>
<p>SubList returns a sub list of the original list between the specified fromIndex, inclusive, and toIndex, exclusive.</p>
<b>Signature:</b>
```go
func (l *List[T]) SubList(fromIndex, toIndex int) *List[T]
```
<b>Example:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
l := list.NewList([]int{1, 2, 3, 4, 5, 6})
fmt.Println(l.SubList(2, 5)) // []int{3, 4, 5}
}
```
### <span id="DeleteIf">DeleteIf</span>
<p>DeleteIf delete all satisfying f(data[i]), returns count of removed elements</p>
<b>Signature:</b>
```go
func (l *List[T]) DeleteIf(f func(T) bool) int
```
<b>Example:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
l := list.NewList([]int{1, 1, 1, 1, 2, 3, 1, 1, 4, 1, 1, 1, 1, 1, 1})
fmt.Println(l.DeleteIf(func(a int) bool { return a == 1 })) // 12
fmt.Println(l.Data()) // []int{2, 3, 4}
}
```

View File

@@ -26,11 +26,15 @@ import (
- [Data](#Data)
- [ValueOf](#ValueOf)
- [IndexOf](#IndexOf)
- [LastIndexOf](#LastIndexOf)
- [IndexOfFunc](#IndexOfFunc)
- [LastIndexOfFunc](#LastIndexOfFunc)
- [Push](#Push)
- [PopFirst](#PopFirst)
- [PopLast](#PopLast)
- [DeleteAt](#DeleteAt)
- [InsertAt](#InsertAt)
- [UpdateAt](#UpdateAt)
- [Equal](#Equal)
- [IsEmpty](#IsEmpty)
@@ -38,11 +42,14 @@ import (
- [Clone](#Clone)
- [Merge](#Merge)
- [Size](#Size)
- [Cap](#Cap)
- [Swap](#Swap)
- [Reverse](#Reverse)
- [Unique](#Unique)
- [Union](#Union)
- [Intersection](#Intersection)
- [SubList](#SubList)
- [DeleteIf](#DeleteIf)
<div STYLE="page-break-after: always;"></div>
@@ -192,6 +199,85 @@ func main() {
```
### <span id="LastIndexOf">LastIndexOf</span>
<p>返回列表中最后一次出现的值的索引。如果未找到,则返回-1</p>
<b>函数签名:</b>
```go
func (l *List[T]) LastIndexOf(value T) int
```
<b>例子:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
li := list.NewList([]int{1, 2, 3, 1})
fmt.Println(li.LastIndexOf(1)) // 3
fmt.Println(li.LastIndexOf(0)) //-1
}
```
### <span id="IndexOfFunc">IndexOfFunc</span>
<p>返回第一个符合函数条件的元素的索引。如果未找到,则返回-1</p>
<b>函数签名:</b>
```go
func (l *List[T]) IndexOfFunc(f func(T) bool) int
```
<b>例子:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
li := list.NewList([]int{1, 2, 3})
fmt.Println(li.IndexOfFunc(func(a int) bool { return a == 1 })) //0
fmt.Println(li.IndexOfFunc(func(a int) bool { return a == 0 })) //-1
}
```
### <span id="LastIndexOfFunc">LastIndexOfFunc</span>
<p>返回最后一个符合函数条件的元素的索引。如果未找到,则返回-1</p>
<b>函数签名:</b>
```go
func (l *List[T]) LastIndexOfFunc(f func(T) bool) int
```
<b>例子:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
li := list.NewList([]int{1, 2, 3, 1})
fmt.Println(li.LastIndexOfFunc(func(a int) bool { return a == 1 })) // 3
fmt.Println(li.LastIndexOfFunc(func(a int) bool { return a == 0 })) //-1
}
```
### <span id="Push">Push</span>
<p>将值附加到列表末尾</p>
@@ -566,6 +652,34 @@ func main() {
### <span id="Cap">Cap</span>
<p>返回列表数据容量</p>
<b>函数签名:</b>
```go
func (l *List[T]) Cap() int
```
<b>例子:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
data := make([]int, 0, 100)
li := list.NewList(data)
fmt.Println(li.Cap()) // 100
}
```
### <span id="Swap">Swap</span>
<p>交换列表中两个索引位置的值</p>
@@ -709,4 +823,60 @@ func main() {
fmt.Println(li3.Data()) //4
}
```
### <span id="SubList">SubList</span>
<p>SubList returns a sub list of the original list between the specified fromIndex, inclusive, and toIndex, exclusive.</p>
<b>函数签名:</b>
```go
func (l *List[T]) SubList(fromIndex, toIndex int) *List[T]
```
<b>例子:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
l := list.NewList([]int{1, 2, 3, 4, 5, 6})
fmt.Println(l.SubList(2, 5)) // []int{3, 4, 5}
}
```
### <span id="DeleteIf">DeleteIf</span>
<p>删除列表中所有符合函数调用函数返回true)的元素,返回删除元素的数量</p>
<b>函数签名:</b>
```go
func (l *List[T]) DeleteIf(f func(T) bool) int
```
<b>例子:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
l := list.NewList([]int{1, 1, 1, 1, 2, 3, 1, 1, 4, 1, 1, 1, 1, 1, 1})
fmt.Println(l.DeleteIf(func(a int) bool { return a == 1 })) // 12
fmt.Println(l.Data()) // []int{2, 3, 4}
}
```

View File

@@ -27,7 +27,7 @@ import (
- [Merge](#Merge)
- [Minus](#Minus)
- [Values](#Values)
- [Values](#Values)
- [IsDisjoint](#IsDisjoint)
<div STYLE="page-break-after: always;"></div>
@@ -305,7 +305,7 @@ func main() {
```
### <span id="IsDisjoint">IsDisjoint</span>
<p>Checks two are disjoint if they have no keys in common</p>
<p>Checks two maps are disjoint if they have no keys in common</p>
<b>Signature:</b>

View File

@@ -20,6 +20,7 @@ import (
<div STYLE="page-break-after: always;"></div>
## Index
- [AppendIfAbsent](#AppendIfAbsent)
- [Contain](#Contain)
- [ContainSubSlice](#ContainSubSlice)
- [Chunk](#Chunk)
@@ -69,6 +70,33 @@ import (
## Documentation
### <span id="AppendIfAbsent">AppendIfAbsent</span>
<p>If slice doesn't contain the value, append it to the slice.</p>
<b>Signature:</b>
```go
func AppendIfAbsent[T comparable](slice []T, value T) []T
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
strs := []string{"a", "b"}
res1 := slice.AppendIfAbsent(strs, "a")
fmt.Println(res1) //[]string{"a", "b"}
res2 := slice.AppendIfAbsent(strs, "cannot")
fmt.Println(res2"}
}
```
### <span id="Contain">Contain</span>
<p>Check if the value is in the slice or not.</p>

View File

@@ -20,6 +20,7 @@ import (
<div STYLE="page-break-after: always;"></div>
## 目录
- [AppendIfAbsent](#AppendIfAbsent)
- [Contain](#Contain)
- [ContainSubSlice](#ContainSubSlice)
- [Chunk](#Chunk)
@@ -69,6 +70,34 @@ import (
## 文档
### <span id="AppendIfAbsent">AppendIfAbsent</span>
<p>当前切片中不包含值时,将该值追加到切片中</p>
<b>函数签名:</b>
```go
func AppendIfAbsent[T comparable](slice []T, value T) []T
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
strs := []string{"a", "b"}
res1 := slice.AppendIfAbsent(strs, "a")
fmt.Println(res1) //[]string{"a", "b"}
res2 := slice.AppendIfAbsent(strs, "cannot")
fmt.Println(res2"}
}
```
### <span id="Contain">Contain</span>
<p>判断slice是否包含value</p>

View File

@@ -116,7 +116,7 @@ func TestDebounced(t *testing.T) {
}
func TestSchedule(t *testing.T) {
assert := internal.NewAssert(t, "TestSchedule")
// assert := internal.NewAssert(t, "TestSchedule")
var res []string
appendStr := func(s string) {
@@ -127,6 +127,10 @@ func TestSchedule(t *testing.T) {
time.Sleep(5 * time.Second)
close(stop)
expected := []string{"*", "*", "*", "*", "*"}
assert.Equal(expected, res)
t.Log(res)
// todo: in github action, for now, this test is not working sometimes
// res maybe [* * * * *] or [* * * * * *]
// expected := []string{"*", "*", "*", "*", "*"}
// assert.Equal(expected, res)
}

View File

@@ -18,7 +18,6 @@ func TestHttpGet(t *testing.T) {
resp, err := HttpGet(url, header)
if err != nil {
log.Fatal(err)
t.FailNow()
}
body, _ := ioutil.ReadAll(resp.Body)
@@ -40,7 +39,6 @@ func TestHttpPost(t *testing.T) {
resp, err := HttpPost(url, header, nil, bodyParams)
if err != nil {
log.Fatal(err)
t.FailNow()
}
body, _ := ioutil.ReadAll(resp.Body)
t.Log("response: ", resp.StatusCode, string(body))
@@ -67,7 +65,6 @@ func TestHttpPostFormData(t *testing.T) {
resp, err := HttpPost(apiUrl, header, postData, nil)
if err != nil {
log.Fatal(err)
t.FailNow()
}
body, _ := ioutil.ReadAll(resp.Body)
t.Log("response: ", resp.StatusCode, string(body))
@@ -89,7 +86,6 @@ func TestHttpPut(t *testing.T) {
resp, err := HttpPut(url, header, nil, bodyParams)
if err != nil {
log.Fatal(err)
t.FailNow()
}
body, _ := ioutil.ReadAll(resp.Body)
t.Log("response: ", resp.StatusCode, string(body))
@@ -111,7 +107,6 @@ func TestHttpPatch(t *testing.T) {
resp, err := HttpPatch(url, header, nil, bodyParams)
if err != nil {
log.Fatal(err)
t.FailNow()
}
body, _ := ioutil.ReadAll(resp.Body)
t.Log("response: ", resp.StatusCode, string(body))
@@ -122,7 +117,6 @@ func TestHttpDelete(t *testing.T) {
resp, err := HttpDelete(url)
if err != nil {
log.Fatal(err)
t.FailNow()
}
body, _ := ioutil.ReadAll(resp.Body)
t.Log("response: ", resp.StatusCode, string(body))
@@ -148,7 +142,6 @@ func TestParseResponse(t *testing.T) {
resp, err := HttpGet(url, header)
if err != nil {
log.Fatal(err)
t.FailNow()
}
type Todo struct {
@@ -162,7 +155,6 @@ func TestParseResponse(t *testing.T) {
err = ParseHttpResponse(resp, toDoResp)
if err != nil {
log.Fatal(err)
t.FailNow()
}
t.Log("response: ", toDoResp)
}

View File

@@ -14,13 +14,13 @@ import (
// Contain check if the value is in the slice or not
func Contain[T comparable](slice []T, value T) bool {
set := make(map[T]struct{}, len(slice))
for _, v := range slice {
if v == value {
return true
}
set[v] = struct{}{}
}
return false
_, ok := set[value]
return ok
}
// ContainSubSlice check if the slice contain subslice or not
@@ -851,3 +851,11 @@ func ToSlice[T any](value ...T) []T {
}
return out
}
// AppendIfAbsent only absent append the value
func AppendIfAbsent[T comparable](slice []T, value T) []T {
if !Contain(slice, value) {
slice = append(slice, value)
}
return slice
}

View File

@@ -609,3 +609,11 @@ func TestToSlicePointer(t *testing.T) {
assert.Equal([]*string{&str1}, ToSlicePointer(str1))
assert.Equal([]*string{&str1, &str2}, ToSlicePointer(str1, str2))
}
func TestAppendIfAbsent(t *testing.T) {
assert := internal.NewAssert(t, "TestAppendIfAbsent")
str1 := []string{"a", "b"}
assert.Equal([]string{"a", "b"}, AppendIfAbsent(str1, "a"))
assert.Equal([]string{"a", "b", "c"}, AppendIfAbsent(str1, "c"))
}