160 lines
4.6 KiB
Go
160 lines
4.6 KiB
Go
// Package op_array ...
|
|
//
|
|
// Description : op_array ...
|
|
//
|
|
// Author : go_developer@163.com<白茶清欢>
|
|
//
|
|
// Date : 2025-11-25 11:30
|
|
package op_array
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
)
|
|
|
|
// ToMap 数组转map
|
|
func ToMap[Key comparable, Value any](dataList []Value, keyFormat func(item Value) Key) map[Key]Value {
|
|
res := make(map[Key]Value)
|
|
for _, item := range dataList {
|
|
key := keyFormat(item)
|
|
res[key] = item
|
|
}
|
|
return res
|
|
}
|
|
|
|
// ToCustomMap 数组转map
|
|
func ToCustomMap[Key comparable, Value any, CustomValue any](dataList []Value, keyFormat func(item Value) Key, formatCustomValue func(item Value) CustomValue) map[Key]CustomValue {
|
|
res := make(map[Key]CustomValue)
|
|
for _, item := range dataList {
|
|
key := keyFormat(item)
|
|
res[key] = formatCustomValue(item)
|
|
}
|
|
return res
|
|
}
|
|
|
|
// ExtractField 提取数组指定字段, 并构建成一个新的数组
|
|
func ExtractField[FieldValue any, Value any](dataList []Value, fieldValue func(item Value) FieldValue) []FieldValue {
|
|
res := make([]FieldValue, 0)
|
|
for _, item := range dataList {
|
|
v := fieldValue(item)
|
|
res = append(res, v)
|
|
}
|
|
return res
|
|
}
|
|
|
|
// Filter 过滤列表数据
|
|
func Filter[Value any](dataList []Value, filterValue func(item Value) bool) []Value {
|
|
res := make([]Value, 0)
|
|
for _, item := range dataList {
|
|
if filterValue(item) {
|
|
res = append(res, item)
|
|
}
|
|
}
|
|
return res
|
|
}
|
|
|
|
// Group 按照指定字段进行分组
|
|
func Group[Key comparable, Value any](dataList []Value, keyFormat func(item Value) Key) [][]Value {
|
|
keyList := make([]string, 0)
|
|
dataTable := make(map[string][]Value)
|
|
res := make([][]Value, 0)
|
|
for _, item := range dataList {
|
|
key := fmt.Sprintf("%v", keyFormat(item))
|
|
if _, ok := dataTable[key]; !ok {
|
|
keyList = append(keyList, key)
|
|
}
|
|
dataTable[key] = append(dataTable[key], item)
|
|
}
|
|
formatList := make([][]Value, 0)
|
|
for _, key := range keyList {
|
|
formatList = append(formatList, dataTable[key])
|
|
}
|
|
return res
|
|
}
|
|
|
|
// TreeItem 数据结构
|
|
type TreeItem[ID comparable, Value any] struct {
|
|
ID ID `json:"id" dc:"数据ID"`
|
|
ParentID ID `json:"parent_id" dc:"父级ID"`
|
|
Value Value `json:"value" dc:"数据值"`
|
|
ChildList []*TreeItem[ID, Value] `json:"child_list" dc:"子级数据列表"`
|
|
}
|
|
|
|
// Tree 将列表数据转为属性结构
|
|
func Tree[ID comparable, Value any](dataList []Value, formatParentID func(v Value) ID, formatID func(v Value) ID) *TreeItem[ID, Value] {
|
|
// list 转table
|
|
dataTable := make(map[ID]*TreeItem[ID, Value])
|
|
for _, item := range dataList {
|
|
dataID := formatID(item)
|
|
dataTable[dataID] = &TreeItem[ID, Value]{
|
|
ID: dataID,
|
|
ParentID: formatParentID(item),
|
|
Value: item,
|
|
ChildList: make([]*TreeItem[ID, Value], 0),
|
|
}
|
|
}
|
|
// 构建树(保证一定是一棵树)
|
|
rootData := &TreeItem[ID, Value]{
|
|
ID: *new(ID),
|
|
ParentID: *new(ID),
|
|
Value: *new(Value),
|
|
ChildList: make([]*TreeItem[ID, Value], 0), // 子数据列表
|
|
}
|
|
for _, item := range dataList {
|
|
dataID := formatID(item)
|
|
parentID := formatParentID(item)
|
|
if _, exist := dataTable[parentID]; exist {
|
|
// 归属某一个父级节点
|
|
dataTable[parentID].ChildList = append(dataTable[parentID].ChildList, dataTable[dataID])
|
|
} else {
|
|
// 部署于任何父节点, 则归属于虚拟的根节点
|
|
rootData.ChildList = append(rootData.ChildList, dataTable[dataID])
|
|
}
|
|
}
|
|
return rootData
|
|
}
|
|
|
|
// DeepClone 深度克隆一个数组, 每一个元素的地址均重新分配
|
|
func DeepClone[Value any](dataList []Value) []Value {
|
|
v := *new(Value)
|
|
vType := reflect.TypeOf(v)
|
|
res := make([]Value, len(dataList))
|
|
for i := 0; i < len(dataList); i++ {
|
|
newV := new(Value)
|
|
switch vType.Kind() {
|
|
case reflect.Ptr:
|
|
// 解引用, 并单独读取值后重新分配地址
|
|
copyV := reflect.New(vType.Elem()).Elem()
|
|
copyV.Set(reflect.ValueOf(dataList[i]).Elem())
|
|
*newV = copyV.Addr().Interface().(Value)
|
|
case reflect.Map:
|
|
mapVal := reflect.ValueOf(dataList[i])
|
|
mapKeyList := mapVal.MapKeys()
|
|
newMap := reflect.MakeMap(vType)
|
|
for _, key := range mapKeyList {
|
|
// 通过键获取对应的值
|
|
value := mapVal.MapIndex(key)
|
|
newMap.SetMapIndex(key, value)
|
|
}
|
|
*newV = newMap.Interface().(Value)
|
|
default:
|
|
*newV = dataList[i]
|
|
}
|
|
res[i] = *newV
|
|
}
|
|
return res
|
|
}
|
|
|
|
// Shard 将数组按照指定数量进行分片
|
|
func Shard[Value any](dataList []Value, itemShardCount int) [][]Value {
|
|
res := make([][]Value, 0)
|
|
for i := 0; i < len(dataList); i += itemShardCount {
|
|
tmpList := make([]Value, 0)
|
|
for j := 0; j < itemShardCount; j++ {
|
|
tmpList = append(tmpList, dataList[i+j])
|
|
}
|
|
res = append(res, tmpList)
|
|
}
|
|
return res
|
|
}
|