Compare commits
8 Commits
master
...
feature/ar
| Author | SHA1 | Date | |
|---|---|---|---|
| efdd850e77 | |||
| 30c1d54f49 | |||
| b0d0a6db28 | |||
| 98f7414d9e | |||
| 38ff576682 | |||
| 2cbffbd883 | |||
| d3eb702c74 | |||
| 54262a7525 |
1
go.mod
1
go.mod
@ -27,6 +27,7 @@ require (
|
||||
github.com/smarty/assertions v1.15.0 // indirect
|
||||
github.com/tidwall/match v1.2.0 // indirect
|
||||
github.com/tidwall/pretty v1.2.1 // indirect
|
||||
github.com/tidwall/sjson v1.2.5 // indirect
|
||||
golang.org/x/mod v0.9.0 // indirect
|
||||
golang.org/x/sys v0.6.0 // indirect
|
||||
golang.org/x/tools v0.7.0 // indirect
|
||||
|
||||
3
go.sum
3
go.sum
@ -44,6 +44,7 @@ github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0b
|
||||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
|
||||
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
@ -52,6 +53,8 @@ github.com/tidwall/match v1.2.0/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JT
|
||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
|
||||
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
|
||||
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
|
||||
golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs=
|
||||
golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||
|
||||
159
op_array/util.go
Normal file
159
op_array/util.go
Normal file
@ -0,0 +1,159 @@
|
||||
// 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
|
||||
}
|
||||
70
op_array/util_test.go
Normal file
70
op_array/util_test.go
Normal file
@ -0,0 +1,70 @@
|
||||
// Package op_array ...
|
||||
//
|
||||
// Description : op_array ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2025-11-27 12:40
|
||||
package op_array
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"git.zhangdeman.cn/zhangdeman/serialize"
|
||||
)
|
||||
|
||||
func TestTree(t *testing.T) {
|
||||
type Data struct {
|
||||
ID int `json:"id" dc:"数据ID"`
|
||||
ParentID int `json:"parent_id" dc:"父级ID"`
|
||||
Value string `json:"value" dc:"数据值"`
|
||||
}
|
||||
|
||||
dataList := []Data{
|
||||
{ID: 1, ParentID: 0, Value: "1"},
|
||||
{ID: 2, ParentID: 1, Value: "2"},
|
||||
{ID: 3, ParentID: 1, Value: "3"},
|
||||
{ID: 4, ParentID: 2, Value: "4"},
|
||||
{ID: 5, ParentID: 2, Value: "5"},
|
||||
{ID: 6, ParentID: 3, Value: "6"},
|
||||
{ID: 7, ParentID: 3, Value: "7"},
|
||||
}
|
||||
res := Tree(dataList, func(v Data) int { return v.ParentID }, func(v Data) int { return v.ID })
|
||||
serialize.JSON.ConsoleOutput(res)
|
||||
}
|
||||
|
||||
func TestClone(t *testing.T) {
|
||||
type Data struct {
|
||||
ID int `json:"id" dc:"数据ID"`
|
||||
}
|
||||
|
||||
// 字面结构体
|
||||
dataList := []Data{
|
||||
{ID: 1},
|
||||
{ID: 2},
|
||||
}
|
||||
res := DeepClone(dataList)
|
||||
fmt.Println(fmt.Sprintf("%p", &res[0]), fmt.Sprintf("%p", &dataList[0]))
|
||||
fmt.Println(fmt.Sprintf("%p", &res[1]), fmt.Sprintf("%p", &dataList[1]))
|
||||
|
||||
// 结构体指针
|
||||
dataList1 := []*Data{
|
||||
{ID: 1},
|
||||
{ID: 2},
|
||||
}
|
||||
res1 := DeepClone(dataList1)
|
||||
fmt.Println(fmt.Sprintf("%p", &res1[0]), fmt.Sprintf("%p", &dataList1[0]))
|
||||
fmt.Println(fmt.Sprintf("%p", &res1[1]), fmt.Sprintf("%p", &dataList1[1]))
|
||||
|
||||
// Map数据
|
||||
dataList2 := []map[string]any{
|
||||
{"id": 1},
|
||||
{"id": 2},
|
||||
}
|
||||
res2 := DeepClone(dataList2)
|
||||
fmt.Println(fmt.Sprintf("%p", &res2[0]), fmt.Sprintf("%p", &dataList2[0]))
|
||||
fmt.Println(fmt.Sprintf("%p", &res2[1]), fmt.Sprintf("%p", &dataList2[1]))
|
||||
serialize.JSON.ConsoleOutput(res2)
|
||||
serialize.JSON.ConsoleOutput(dataList2)
|
||||
}
|
||||
Reference in New Issue
Block a user