Skip to content

Commit

Permalink
feat(maputil): add ToSortedSlicesDefault method and ToSortedSlicesWit…
Browse files Browse the repository at this point in the history
…hComparator method (#206)
  • Loading branch information
cannian1 committed Mar 31, 2024
1 parent e9280b8 commit 5e6e8d8
Show file tree
Hide file tree
Showing 5 changed files with 494 additions and 0 deletions.
94 changes: 94 additions & 0 deletions docs/api/packages/maputil.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ import (
- [Minus](#Minus)
- [IsDisjoint](#IsDisjoint)
- [HasKey](#HasKey)
- [ToSortedSlicesDefault](#ToSortedSlicesDefault)
- [ToSortedSlicesWithComparator](#ToSortedSlicesWithComparator)
- [NewConcurrentMap](#NewConcurrentMap)
- [ConcurrentMap_Get](#ConcurrentMap_Get)
- [ConcurrentMap_Set](#ConcurrentMap_Set)
Expand Down Expand Up @@ -988,6 +990,98 @@ func main() {
}
```

### <span id="ToSortedSlicesDefault">ToSortedSlicesDefault</span>

<p>将map的key和value转化成两个根据key的值从小到大排序的切片,value切片中元素的位置与key对应。</p>

<b>函数签名:</b>

```go
func ToSortedSlicesDefault[K constraints.Ordered, V any](m map[K]V) ([]K, []V)
```

<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>

```go
package main

import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)

func main() {
m := map[int]string{
1: "a",
3: "c",
2: "b",
}

keys, values := ToSortedSlicesDefault(m)

fmt.Println(keys)
fmt.Println(values)

// Output:
// [1 2 3]
// [a b c]
}
```

### <span id="ToSortedSlicesWithComparator">ToSortedSlicesWithComparator</span>

<p>将map的key和value转化成两个使用比较器函数根据key的值自定义排序规则的切片,value切片中元素的位置与key对应。</p>

<b>函数签名:</b>

```go
func ToSortedSlicesWithComparator[K comparable, V any](m map[K]V, comparator func(a, b K) bool) ([]K, []V)
```

<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>

```go
package main

import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)

func main() {
m1 := map[time.Time]string{
time.Date(2024, 3, 31, 0, 0, 0, 0, time.UTC): "today",
time.Date(2024, 3, 30, 0, 0, 0, 0, time.UTC): "yesterday",
time.Date(2024, 4, 1, 0, 0, 0, 0, time.UTC): "tomorrow",
}

keys1, values1 := ToSortedSlicesWithComparator(m1, func(a, b time.Time) bool {
return a.Before(b)
})

m2 := map[int]string{
1: "a",
3: "c",
2: "b",
}
keys2, values2 := ToSortedSlicesWithComparator(m2, func(a, b int) bool {
return a > b
})

fmt.Println(keys2)
fmt.Println(values2)

fmt.Println(keys1)
fmt.Println(values1)

// Output:
// [2024-03-30 00:00:00 +0000 UTC 2024-03-31 00:00:00 +0000 UTC 2024-04-01 00:00:00 +0000 UTC]
// [yesterday today tomorrow]
// [3 2 1]
// [c b a]
}
```

### <span id="NewConcurrentMap">NewConcurrentMap</span>

<p>ConcurrentMap协程安全的map结构。</p>
Expand Down
97 changes: 97 additions & 0 deletions docs/en/api/packages/maputil.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ import (
- [Minus](#Minus)
- [IsDisjoint](#IsDisjoint)
- [HasKey](#HasKey)
- [ToSortedSlicesDefault](#ToSortedSlicesDefault)
- [ToSortedSlicesWithComparator](#ToSortedSlicesWithComparator)
- [NewConcurrentMap](#NewConcurrentMap)
- [ConcurrentMap_Get](#ConcurrentMap_Get)
- [ConcurrentMap_Set](#ConcurrentMap_Set)
Expand Down Expand Up @@ -992,6 +994,101 @@ func main() {
}
```

### <span id="ToSortedSlicesDefault">ToSortedSlicesDefault</span>

<p>
Translate the key and value of the map into two slices that are sorted in ascending order according to the key’s value, with the position of the elements in the value slice corresponding to the key.</p>

<b>Signature:</b>

```go
func ToSortedSlicesDefault[K constraints.Ordered, V any](m map[K]V) ([]K, []V)
```

<b>Example:<span style="float:right;display:inline-block;">[Run](Todo)</span></b>

```go
package main

import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)

func main() {
m := map[int]string{
1: "a",
3: "c",
2: "b",
}

keys, values := ToSortedSlicesDefault(m)

fmt.Println(keys)
fmt.Println(values)

// Output:
// [1 2 3]
// [a b c]
}
```

### <span id="ToSortedSlicesWithComparator">ToSortedSlicesWithComparator</span>

<p>
Translate the key and value of the map into two slices that are sorted according to a custom sorting rule defined by a comparator function based on the key's value, with the position of the elements in the value slice corresponding to the key.
</p>

<b>Signature:</b>

```go
func ToSortedSlicesWithComparator[K comparable, V any](m map[K]V, comparator func(a, b K) bool) ([]K, []V)
```

<b>Example:<span style="float:right;display:inline-block;">[Run](Todo)</span></b>

```go
package main

import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)

func main() {
m1 := map[time.Time]string{
time.Date(2024, 3, 31, 0, 0, 0, 0, time.UTC): "today",
time.Date(2024, 3, 30, 0, 0, 0, 0, time.UTC): "yesterday",
time.Date(2024, 4, 1, 0, 0, 0, 0, time.UTC): "tomorrow",
}

keys1, values1 := ToSortedSlicesWithComparator(m1, func(a, b time.Time) bool {
return a.Before(b)
})

m2 := map[int]string{
1: "a",
3: "c",
2: "b",
}
keys2, values2 := ToSortedSlicesWithComparator(m2, func(a, b int) bool {
return a > b
})

fmt.Println(keys2)
fmt.Println(values2)

fmt.Println(keys1)
fmt.Println(values1)

// Output:
// [2024-03-30 00:00:00 +0000 UTC 2024-03-31 00:00:00 +0000 UTC 2024-04-01 00:00:00 +0000 UTC]
// [yesterday today tomorrow]
// [3 2 1]
// [c b a]
}
```

### <span id="NewConcurrentMap">NewConcurrentMap</span>

<p>ConcurrentMap is like map, but is safe for concurrent use by multiple goroutines.</p>
Expand Down
49 changes: 49 additions & 0 deletions maputil/map.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ package maputil

import (
"fmt"
"golang.org/x/exp/constraints"
"reflect"
"sort"

"github.com/duke-git/lancet/v2/slice"
)
Expand Down Expand Up @@ -384,3 +386,50 @@ func getFieldNameByJsonTag(structObj any, jsonTag string) string {

return ""
}

// ToSortedSlicesDefault converts a map to two slices sorted by key: one for the keys and another for the values.
func ToSortedSlicesDefault[K constraints.Ordered, V any](m map[K]V) ([]K, []V) {
keys := make([]K, 0, len(m))

// store the map’s keys into a slice
for k := range m {
keys = append(keys, k)
}

// sort the slice of keys
sort.Slice(keys, func(i, j int) bool {
return keys[i] < keys[j]
})

// adjust the order of values according to the sorted keys
sortedValues := make([]V, len(keys))
for i, k := range keys {
sortedValues[i] = m[k]
}

return keys, sortedValues
}

// ToSortedSlicesWithComparator converts a map to two slices sorted by key and using a custom comparison function:
// one for the keys and another for the values.
func ToSortedSlicesWithComparator[K comparable, V any](m map[K]V, comparator func(a, b K) bool) ([]K, []V) {
keys := make([]K, 0, len(m))

// store the map’s keys into a slice
for k := range m {
keys = append(keys, k)
}

// sort the key slice using the provided comparison function
sort.Slice(keys, func(i, j int) bool {
return comparator(keys[i], keys[j])
})

// adjust the order of values according to the sorted keys
sortedValues := make([]V, len(keys))
for i, k := range keys {
sortedValues[i] = m[k]
}

return keys, sortedValues
}
74 changes: 74 additions & 0 deletions maputil/map_example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"sort"
"strconv"
"time"
)

func ExampleKeys() {
Expand Down Expand Up @@ -450,3 +451,76 @@ func ExampleHasKey() {
// true
// false
}

func ExampleMapToStruct() {

personReqMap := map[string]any{
"name": "Nothin",
"max_age": 35,
"page": 1,
"pageSize": 10,
}

type PersonReq struct {
Name string `json:"name"`
MaxAge int `json:"max_age"`
Page int `json:"page"`
PageSize int `json:"pageSize"`
}
var personReq PersonReq
_ = MapToStruct(personReqMap, &personReq)
fmt.Println(personReq)

// Output:
// {Nothin 35 1 10}
}

func ExampleToSortedSlicesDefault() {
m := map[int]string{
1: "a",
3: "c",
2: "b",
}

keys, values := ToSortedSlicesDefault(m)

fmt.Println(keys)
fmt.Println(values)

// Output:
// [1 2 3]
// [a b c]
}

func ExampleToSortedSlicesWithComparator() {
m1 := map[time.Time]string{
time.Date(2024, 3, 31, 0, 0, 0, 0, time.UTC): "today",
time.Date(2024, 3, 30, 0, 0, 0, 0, time.UTC): "yesterday",
time.Date(2024, 4, 1, 0, 0, 0, 0, time.UTC): "tomorrow",
}

keys1, values1 := ToSortedSlicesWithComparator(m1, func(a, b time.Time) bool {
return a.Before(b)
})

m2 := map[int]string{
1: "a",
3: "c",
2: "b",
}
keys2, values2 := ToSortedSlicesWithComparator(m2, func(a, b int) bool {
return a > b
})

fmt.Println(keys1)
fmt.Println(values1)

fmt.Println(keys2)
fmt.Println(values2)

// Output:
// [2024-03-30 00:00:00 +0000 UTC 2024-03-31 00:00:00 +0000 UTC 2024-04-01 00:00:00 +0000 UTC]
// [yesterday today tomorrow]
// [3 2 1]
// [c b a]
}
Loading

0 comments on commit 5e6e8d8

Please sign in to comment.