1
0
mirror of https://github.com/duke-git/lancet.git synced 2026-02-04 21:02:27 +08:00
Files
lancet/docs/api/packages/maputil.md
2024-07-18 11:44:00 +08:00

28 KiB
Raw Blame History

Maputil

maputil 包包括一些操作 map 的函数。

源码:

用法:

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

目录:

API 文档:

MapTo

快速将map或者其他类型映射到结构体或者指定类型。

函数签名:

func MapTo(src any, dst any) error

示例:运行

package main

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

func main() {
    type (
        Person struct {
            Name  string  `json:"name"`
            Age   int     `json:"age"`
            Phone string  `json:"phone"`
            Addr  Address `json:"address"`
        }

        Address struct {
            Street string `json:"street"`
            Number int    `json:"number"`
        }
    )

    personInfo := map[string]interface{}{
        "name":  "Nothin",
        "age":   28,
        "phone": "123456789",
        "address": map[string]interface{}{
            "street": "test",
            "number": 1,
        },
    }

    var p Person
    err := MapTo(personInfo, &p)

    fmt.Println(err)
    fmt.Println(p)

    // Output:
    // <nil>
    // {Nothin 28 123456789 {test 1}}
}

ForEach

对map中的每对key和value执行iteratee函数

函数签名:

func ForEach[K comparable, V any](m map[K]V, iteratee func(key K, value V))

示例:运行

package main

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

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

    var sum int

    maputil.ForEach(m, func(_ string, value int) {
        sum += value
    })

    fmt.Println(sum)

    // Output:
    // 10
}

Filter

迭代map中的每对key和value, 返回符合predicate函数的key, value。

函数签名:

func Filter[K comparable, V any](m map[K]V, predicate func(key K, value V) bool) map[K]V

示例:运行

package main

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

func main() {
    m := map[string]int{
        "a": 1,
        "b": 2,
        "c": 3,
        "d": 4,
        "e": 5,
    }
    isEven := func(_ string, value int) bool {
        return value%2 == 0
    }

    maputil.Filter(m, func(_ string, value int) {
        sum += value
    })

    result := Filter(m, isEven)

    fmt.Println(result)

    // Output:
    // map[b:2 d:4]
}

FilterByKeys

迭代map, 返回一个新map其key都是给定的key值。

函数签名:

func FilterByKeys[K comparable, V any](m map[K]V, keys []K) map[K]V

示例:运行

package main

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

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

    result := maputil.FilterByKeys(m, []string{"a", "b"})

    fmt.Println(result)

    // Output:
    // map[a:1 b:2]
}

FilterByValues

迭代map, 返回一个新map其value都是给定的value值。

函数签名:

func FilterByValues[K comparable, V comparable](m map[K]V, values []V) map[K]V

示例:运行

package main

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

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

    result := maputil.FilterByValues(m, []int{3, 4})

    fmt.Println(result)

    // Output:
    // map[c:3 d:4]
}

OmitBy

Filter的反向操作, 迭代map中的每对key和value, 删除符合predicate函数的key, value, 返回新map。

函数签名:

func OmitBy[K comparable, V any](m map[K]V, predicate func(key K, value V) bool) map[K]V

示例:运行

package main

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

func main() {
    m := map[string]int{
        "a": 1,
        "b": 2,
        "c": 3,
        "d": 4,
        "e": 5,
    }
    isEven := func(_ string, value int) bool {
        return value%2 == 0
    }

    result := maputil.OmitBy(m, isEven)

    fmt.Println(result)

    // Output:
    // map[a:1 c:3 e:5]
}

OmitByKeys

FilterByKeys的反向操作, 迭代map, 返回一个新map其key不包括给定的key值。

函数签名:

func OmitByKeys[K comparable, V any](m map[K]V, keys []K) map[K]V

示例:运行

package main

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

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

    result := maputil.OmitByKeys(m, []string{"a", "b"})

    fmt.Println(result)

    // Output:
    // map[c:3 d:4 e:5]
}

OmitByValues

FilterByValues的反向操作, 迭代map, 返回一个新map其value不包括给定的value值。

函数签名:

func OmitByValues[K comparable, V comparable](m map[K]V, values []V) map[K]V

示例:运行

package main

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

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

    result := maputil.OmitByValues(m, []int{4, 5})

    fmt.Println(result)

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

Intersect

多个map的交集操作

函数签名:

func Intersect[K comparable, V any](maps ...map[K]V) map[K]V

示例:运行

package main

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

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

    m2 := map[string]int{
        "a": 1,
        "b": 2,
        "c": 6,
        "d": 7,
    }

    m3 := map[string]int{
        "a": 1,
        "b": 9,
        "e": 9,
    }

    result1 := maputil.Intersect(m1)
    result2 := maputil.Intersect(m1, m2)
    result3 := maputil.Intersect(m1, m2, m3)

    fmt.Println(result1)
    fmt.Println(result2)
    fmt.Println(result3)

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

Keys

返回map中所有key的切片

函数签名:

func Keys[K comparable, V any](m map[K]V) []K

示例:运行

package main

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

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

    keys := maputil.Keys(m)
    sort.Ints(keys)

    fmt.Println(keys)

    // Output:
    // [1 2 3 4 5]
}

Merge

合并多个maps, 相同的key会被后来的key覆盖

函数签名:

func Merge[K comparable, V any](maps ...map[K]V) map[K]V

示例:运行

package main

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

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

    result := maputil.Merge(m1, m2)

    fmt.Println(result)

    // Output:
    // map[1:c 2:b 3:d]
}

Minus

返回一个map其中的key存在于mapA不存在于mapB.

函数签名:

func Minus[K comparable, V any](mapA, mapB map[K]V) map[K]V

示例:运行

package main

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

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

    m2 := map[string]int{
        "a": 11,
        "b": 22,
        "d": 33,
    }

    result := maputil.Minus(m1, m2)

    fmt.Println(result)

    // Output:
    // map[c:3]
}

Values

返回map中所有value的切片

函数签名:

func Values[K comparable, V any](m map[K]V) []V

示例:运行

package main

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

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

    values := maputil.Values(m)
    sort.Strings(values)

    // Output:
    // [a a b c d]
}

KeysBy

创建一个切片其元素是每个map的key调用mapper函数的结果。

函数签名:

func KeysBy[K comparable, V any, T any](m map[K]V, mapper func(item K) T) []T

示例:运行

package main

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

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

    keys := maputil.KeysBy(m, func(n int) int {
        return n + 1
    })

    sort.Ints(keys)

    fmt.Println(keys)

    // Output:
    // [2 3 4]
}

ValuesBy

创建一个切片其元素是每个map的value调用mapper函数的结果。

函数签名:

func ValuesBy[K comparable, V any, T any](m map[K]V, mapper func(item V) T) []T

示例:运行

package main

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

func main() {
    m := map[int]string{
        1: "a",
        2: "b",
        3: "c",
    }
    values := maputil.ValuesBy(m, func(v string) string {
        switch v {
        case "a":
            return "a-1"
        case "b":
            return "b-2"
        case "c":
            return "c-3"
        default:
            return ""
        }
    })

    sort.Strings(values)

    fmt.Println(values)

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

MapKeys

操作map的每个key然后转为新的map。

函数签名:

func MapKeys[K comparable, V any, T comparable](m map[K]V, iteratee func(key K, value V) T) map[T]V

示例:运行

package main

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

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

    result := maputil.MapKeys(m, func(k int, _ string) string {
        return strconv.Itoa(k)
    })

    fmt.Println(result)

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

MapValues

操作map的每个value然后转为新的map。

函数签名:

func MapValues[K comparable, V any, T any](m map[K]V, iteratee func(key K, value V) T) map[K]T

示例:运行

package main

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

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

    result := maputil.MapValues(m, func(k int, v string) string {
        return v + strconv.Itoa(k)
    })

    fmt.Println(result)

    // Output:
    // map[1:a1 2:b2 3:c3]
}

Entry

将map转换为键/值对切片。

函数签名:

type Entry[K comparable, V any] struct {
    Key   K
    Value V
}
func Entries[K comparable, V any](m map[K]V) []Entry[K, V]

示例:运行

package main

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

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

    result := maputil.Entries(m)

    sort.Slice(result, func(i, j int) bool {
        return result[i].Value < result[j].Value
    })

    fmt.Println(result)

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

FromEntries

基于键/值对的切片创建map。

函数签名:

type Entry[K comparable, V any] struct {
    Key   K
    Value V
}
func FromEntries[K comparable, V any](entries []Entry[K, V]) map[K]V

示例:运行

package main

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

func main() {
    result := maputil.FromEntries([]Entry[string, int]{
        {Key: "a", Value: 1},
        {Key: "b", Value: 2},
        {Key: "c", Value: 3},
    })

    fmt.Println(result)

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

Transform

将map转换为其他类型的map。

函数签名:

func Transform[K1 comparable, V1 any, K2 comparable, V2 any](m map[K1]V1, iteratee func(key K1, value V1) (K2, V2)) map[K2]V2

示例:运行

package main

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

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

    result := Transform(m, func(k string, v int) (string, string) {
        return k, strconv.Itoa(v)
    })

    fmt.Println(result)

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

IsDisjoint

验证两个map是否具有不同的key

函数签名:

func IsDisjoint[K comparable, V any](mapA, mapB map[K]V) bool

示例:运行

package main

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

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

    m2 := map[string]int{
        "d": 22,
    }

    m3 := map[string]int{
        "a": 22,
    }

    result1 := maputil.IsDisjoint(m1, m2)
    result2 := maputil.IsDisjoint(m1, m3)

    fmt.Println(result1)
    fmt.Println(result2)

    // Output:
    // true
    // false
}

HasKey

检查map是否包含某个key。用于代替以下样板代码:

函数签名:

func HasKey[K comparable, V any](m map[K]V, key K) bool

示例:运行

package main

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

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

    result1 := maputil.HasKey(m, "a")
    result2 := maputil.HasKey(m, "c")

    fmt.Println(result1)
    fmt.Println(result2)

    // Output:
    // true
    // false
}

MapToStruct

将map转成struct。

函数签名:

func MapToStruct(m map[string]any, structObj any) error

示例:运行

package main

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

func main() {
    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
    _ = maputil.MapToStruct(personReqMap, &personReq)
    fmt.Println(personReq)

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

ToSortedSlicesDefault

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

函数签名:

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

示例:运行

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]
}

ToSortedSlicesWithComparator

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

函数签名:

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

示例:运行

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 := maputil.ToSortedSlicesWithComparator(m1, func(a, b time.Time) bool {
        return a.Before(b)
    })

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

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

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

    // Output:
    // [3 2 1]
    // [c b a]
    // [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]
}

NewConcurrentMap

ConcurrentMap协程安全的map结构。

函数签名:

// NewConcurrentMap create a ConcurrentMap with specific shard count.
func NewConcurrentMap[K comparable, V any](shardCount int) *ConcurrentMap[K, V]

示例:运行

package main

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

func main() {
    // create a ConcurrentMap whose key type is string, value type is int
    cm := maputil.NewConcurrentMap[string, int](100)
}

ConcurrentMap_Set

在map中设置key和value。

函数签名:

func (cm *ConcurrentMap[K, V]) Set(key K, value V)

示例:运行

package main

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

func main() {
    cm := maputil.NewConcurrentMap[string, int](100)

    var wg1 sync.WaitGroup
    wg1.Add(5)

    for i := 0; i < 5; i++ {
        go func(n int) {
            cm.Set(fmt.Sprintf("%d", n), n)
            wg1.Done()
        }(i)
    }
    wg1.Wait()

    var wg2 sync.WaitGroup
    wg2.Add(5)
    for j := 0; j < 5; j++ {
        go func(n int) {
            val, ok := cm.Get(fmt.Sprintf("%d", n))
            fmt.Println(val, ok)
            wg2.Done()
        }(j)
    }
    wg2.Wait()

    // output: (order may change)
    // 1 true
    // 3 true
    // 2 true
    // 0 true
    // 4 true
}

ConcurrentMap_Get

根据key获取value, 如果不存在key,返回零值。

函数签名:

func (cm *ConcurrentMap[K, V]) Get(key K) (V, bool)

示例:运行

package main

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

func main() {
    cm := maputil.NewConcurrentMap[string, int](100)

    var wg1 sync.WaitGroup
    wg1.Add(5)

    for i := 0; i < 5; i++ {
        go func(n int) {
            cm.Set(fmt.Sprintf("%d", n), n)
            wg1.Done()
        }(i)
    }
    wg1.Wait()

    var wg2 sync.WaitGroup
    wg2.Add(5)
    for j := 0; j < 5; j++ {
        go func(n int) {
            val, ok := cm.Get(fmt.Sprintf("%d", n))
            fmt.Println(val, ok)
            wg2.Done()
        }(j)
    }
    wg2.Wait()

    // output: (order may change)
    // 1 true
    // 3 true
    // 2 true
    // 0 true
    // 4 true
}

ConcurrentMap_GetOrSet

返回键的现有值如果存在否则设置key并返回给定值。

函数签名:

func (cm *ConcurrentMap[K, V]) GetOrSet(key K, value V) (actual V, ok bool)

示例:运行

package main

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

func main() {
    cm := maputil.NewConcurrentMap[string, int](100)

    var wg sync.WaitGroup
    wg.Add(5)

    for i := 0; i < 5; i++ {
        go func(n int) {
            val, ok := cm.GetOrSet(fmt.Sprintf("%d", n), n)
            fmt.Println(val, ok)
            wg.Done()
        }(i)
    }
    wg.Wait()

    // output: (order may change)
    // 1 false
    // 3 false
    // 2 false
    // 0 false
    // 4 false
}

ConcurrentMap_Delete

删除key。

函数签名:

func (cm *ConcurrentMap[K, V]) Delete(key K)

示例:运行

package main

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

func main() {
    cm := maputil.NewConcurrentMap[string, int](100)

    var wg1 sync.WaitGroup
    wg1.Add(5)

    for i := 0; i < 5; i++ {
        go func(n int) {
            cm.Set(fmt.Sprintf("%d", n), n)
            wg1.Done()
        }(i)
    }
    wg1.Wait()

    var wg2 sync.WaitGroup
    wg2.Add(5)
    for j := 0; j < 5; j++ {
        go func(n int) {
            cm.Delete(fmt.Sprintf("%d", n))
            wg2.Done()
        }(i)
    }
    wg2.Wait()
}

ConcurrentMap_GetAndDelete

获取key然后删除。

函数签名:

func (cm *ConcurrentMap[K, V]) GetAndDelete(key K) (actual V, ok bool)

示例:运行

package main

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

func main() {
    cm := maputil.NewConcurrentMap[string, int](100)

    var wg1 sync.WaitGroup
    wg1.Add(5)

    for i := 0; i < 5; i++ {
        go func(n int) {
            cm.Set(fmt.Sprintf("%d", n), n)
            wg1.Done()
        }(i)
    }
    wg1.Wait()

    var wg2 sync.WaitGroup
    wg2.Add(5)
    for j := 0; j < 5; j++ {
        go func(n int) {
            val, ok := cm.GetAndDelete(fmt.Sprintf("%d", n))
            fmt.Println(val, ok) //n, true

            _, ok = cm.Get(fmt.Sprintf("%d", n))
            fmt.Println(val, ok) //false

            wg2.Done()
        }(j)
    }
    wg2.Wait()
}

ConcurrentMap_Has

验证是否包含key。

函数签名:

func (cm *ConcurrentMap[K, V]) Has(key K) bool

示例:运行

package main

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

func main() {
    cm := maputil.NewConcurrentMap[string, int](100)

    var wg1 sync.WaitGroup
    wg1.Add(5)
    for i := 0; i < 5; i++ {
        go func(n int) {
            cm.Set(fmt.Sprintf("%d", n), n)
            wg1.Done()
        }(i)
    }
    wg1.Wait()

    var wg2 sync.WaitGroup
    wg2.Add(5)

    for j := 0; j < 5; j++ {
        go func(n int) {
            ok := cm.Has(fmt.Sprintf("%d", n))
            fmt.Println(ok) // true

            wg2.Done()
        }(j)
    }
    wg2.Wait()
}

ConcurrentMap_Range

为map中每个键和值顺序调用迭代器。 如果iterator返回false则停止迭代。

函数签名:

func (cm *ConcurrentMap[K, V]) Range(iterator func(key K, value V) bool)

示例:运行

package main

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

func main() {
    cm := maputil.NewConcurrentMap[string, int](100)

    var wg1 sync.WaitGroup
    wg1.Add(5)

    for i := 0; i < 5; i++ {
        go func(n int) {
            cm.Set(fmt.Sprintf("%d", n), n)
            wg1.Done()
        }(i)
    }
    wg1.Wait()


    cm.Range(func(key string, value int) bool {
        fmt.Println(value)
        return true
    })
}

GetOrSet

返回给定键的值,如果不存在则设置该值。

函数签名:

func GetOrSet[K comparable, V any](m map[K]V, key K, value V) V

示例:运行

package main

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

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

    result1 := maputil.GetOrSet(m, 1, "1")
    result2 := maputil.GetOrSet(m, 2, "b")

    fmt.Println(result1)
    fmt.Println(result2)

    // Output:
    // a
    // b
}