合规国际互联网加速 OSASE为企业客户提供高速稳定SD-WAN国际加速解决方案。 广告
~~~ /* Package toolutilv4 提供了一组通用切片函数, 函数目录: - AppendHead(AppendHeadInt,AppendHeadStr,AppendHeadSliceMap) 在切片头部追加一个整数元素,并返回新的切片 - Contains(ContainsInt,ContainStr) 检查给定的切片中是否存在某个元素 - ConvertSliceToMap 将结构体切片转出[]map[string]interface{} - FindDiffVales(FindDiffValesInt,FindDiffValesStr) 找到两个切片中不同的元素,返回两个切片中不同元素组成的切片 - FindSameVales(FindSameValesInt,FindSameValesStr) 找到两个切片中同同的元素,返回两个切片中相同同元素组成的切片 - FindOutVales(FindOutValesInt,FindOutValesStr) 从slice1里剔除slice2存在的值 - FilterSlice 模糊搜索 - GroupByKey 将[]map[string]interface{}按某个字段分组 - MapListKeyToSlice(MapListKeyToSliceInt, MapListKeyToSliceStr) 从输入的 []map[string]interface{} 类型的切片中提取指定 key 对应的类型数值,并返回一个对应类型的切片 - MoveToFirst 移动第一位 - Paginate 分页 - RemoveKeysFromMaps 删除指定key - Unique(UniqueInt, UniqueString) 切片去重 - SortByKey 函数按照指定的 key 对应的值,对输入的 []map[string]interface{} 类型的切片进行排序。 - StringToSlice(StringToSliceInt, StringToSliceStr) 将字符串解析为对应切片类型 */ package toolutilv4 import ( "encoding/json" "fmt" "reflect" "sort" "strings" ) var ToolSlice = toolSliceUtil{} type toolSliceUtil struct{} // AppendHeadInt 在切片头部追加一个整数元素,并返回新的切片 func (s *toolSliceUtil) AppendHeadInt(slice []int, addData int) []int { return append([]int{addData}, slice...) } // AppendHeadStr 在切片头部追加一个整数元素,并返回新的切片 func (s *toolSliceUtil) AppendHeadStr(slice []string, addData string) []string { return append([]string{addData}, slice...) } // AppendHeadSliceMap 在切片头部追加一个整数元素,并返回新的切片 func (s *toolSliceUtil) AppendHeadSliceMap(slice []map[string]interface{}, addData map[string]interface{}) []map[string]interface{} { // 创建一个新的切片,容量为原切片长度加1 newSlice := make([]map[string]interface{}, len(slice)+1) // 在新切片的开头添加 addData 元素 newSlice[0] = addData // 将原切片的元素拷贝到新切片中,从索引1开始,覆盖掉原切片的位置 copy(newSlice[1:], slice) // 返回新的切片 return newSlice } // ContainsInt 检查给定的切片中是否存在某个元素 func (s *toolSliceUtil) ContainsInt(slice []int, item int) bool { // 遍历整个切片 for i := 0; i < len(slice); i++ { // 比较切片中的元素和要查找的元素 if slice[i] == item { return true } } // 如果循环结束仍未找到匹配项,则返回false return false } // ContainStr 方法可以检查给定的切片中是否存在某个元素 func (s *toolSliceUtil) ContainStr(slice []string, item string) bool { // 遍历整个切片 for i := 0; i < len(slice); i++ { // 比较切片中的元素和要查找的元素 if slice[i] == item { return true } } // 如果循环结束仍未找到匹配项,则返回false return false } /* 该函数接受一个参数 slice,可以接受任何类型的切片结构体。 在函数内部,我们首先使用反射获取传入参数的值和类型,然后遍历每个结构体实例,将其转换为 map[string]interface{} 类型,并添加到结果切片中。最后,返回转换好的切片。 如果传入的参数不是切片类型或者切片元素不是结构体类型,函数会返回一个错误 not a slice 或者 not a struct。这可以防止代码在运行时出现崩溃或者异常情况。 */ // ConvertSliceToMap 将结构体切片转出[]map[string]interface{} func (s *toolSliceUtil) ConvertSliceToMap(slice interface{}) []map[string]interface{} { // 获取slice的值 sliceValue := reflect.ValueOf(slice) // 检查slice是否为切片类型 if sliceValue.Kind() != reflect.Slice { return []map[string]interface{}{} } // 创建一个空的map切片,用于存储转换后的结果 var result []map[string]interface{} // 遍历整个slice for i := 0; i < sliceValue.Len(); i++ { // 获取当前元素 item := sliceValue.Index(i) // 获取当前元素的值 itemValue := reflect.ValueOf(item.Interface()) // 检查当前元素是否为结构体类型 if itemValue.Kind() != reflect.Struct { return []map[string]interface{}{} } // 创建一个空的map,用于存储当前元素的字段名和对应的值 itemMap := make(map[string]interface{}) // 遍历当前元素的所有字段 for j := 0; j < itemValue.NumField(); j++ { // 获取当前字段的名称 fieldName := itemValue.Type().Field(j).Name // 获取当前字段的值 fieldValue := itemValue.Field(j).Interface() // 将字段名和对应的值添加到map中 itemMap[fieldName] = fieldValue } // 将当前元素转换为map后,将其添加到结果切片中 result = append(result, itemMap) } return result } // FindDiffValesInt 找到两个切片中不同的元素,返回两个切片中不同元素组成的切片 func (s *toolSliceUtil) FindDiffValesInt(slice1 []int, slice2 []int) []int { // 创建一个空的切片,用于存储不同的元素 diffVals := make([]int, 0) // 使用map存储第一个切片中的元素,以便快速查找 lookup := make(map[int]struct{}) for _, val := range slice1 { lookup[val] = struct{}{} } // 遍历第二个切片 for _, val := range slice2 { // 如果第二个切片中的元素不在第一个切片中,则添加到不同值切片中 if _, ok := lookup[val]; !ok { diffVals = append(diffVals, val) } } // 返回两个切片中不同元素组成的切片 return diffVals } // FindDiffValesStr找到两个切片中不同的元素,返回两个切片中不同元素组成的切片 func (s *toolSliceUtil) FindDiffValesStr(slice1 []string, slice2 []string) []string { // 创建一个空的切片,用于存储不同的元素 diffVals := make([]string, 0) // 使用map存储第一个切片中的元素,以便快速查找 lookup := make(map[string]struct{}) for _, val := range slice1 { lookup[val] = struct{}{} } // 遍历第二个切片 for _, val := range slice2 { // 如果第二个切片中的元素不在第一个切片中,则添加到不同值切片中 if _, ok := lookup[val]; !ok { diffVals = append(diffVals, val) } } // 返回两个切片中不同元素组成的切片 return diffVals } // FindSameValesInt 找到两个切片中同同的元素,返回两个切片中相同同元素组成的切片 func (s *toolSliceUtil) FindSameValesInt(slice1 []int, slice2 []int) []int { sameVals := make([]int, 0) // 使用map存储第一个切片中的元素,以便快速查找 lookup := make(map[int]struct{}) for _, val := range slice1 { lookup[val] = struct{}{} } // 遍历第二个切片 for _, val := range slice2 { // 如果第二个切片中的元素在第一个切片中,则添加到相同值切片中 if _, ok := lookup[val]; ok { sameVals = append(sameVals, val) } } // 返回两个切片中相同元素组成的切片 return sameVals } // FindSameValesStr 找到两个切片中同同的元素,返回两个切片中相同同元素组成的切片 func (s *toolSliceUtil) FindSameValesStr(slice1 []string, slice2 []string) []string { sameVals := make([]string, 0) // 使用map存储第一个切片中的元素,以便快速查找 lookup := make(map[string]struct{}) for _, val := range slice1 { lookup[val] = struct{}{} } // 遍历第二个切片 for _, val := range slice2 { // 如果第二个切片中的元素在第一个切片中,则添加到相同值切片中 if _, ok := lookup[val]; ok { sameVals = append(sameVals, val) } } // 返回两个切片中相同元素组成的切片 return sameVals } func (s *toolSliceUtil) FindSameValesOfInt(slice1 []int, slice2 []int) []int { sameVales := make([]int, 0) // 遍历第一个切片 for _, val1 := range slice1 { // 在第二个切片中查找相同值 for _, val2 := range slice2 { if val1 == val2 { sameVales = append(sameVales, val1) break } } } return sameVales } // FindOutValesInt 从slice1里剔除slice2存在的值 func (s *toolSliceUtil) FindOutValesInt(slice1 []int, slice2 []int) []int { // 创建一个map,用于存储slice2中出现的所有元素 m := make(map[int]bool) for _, i := range slice2 { m[i] = true } // 创建一个空的切片,用于存储slice1中不同于slice2的元素 var result []int for _, i := range slice1 { if !m[i] { result = append(result, i) } } // 返回slice2独有的元素组成的切片 return result } // FindOutValesStr 从slice1里剔除slice2存在的值 func (s *toolSliceUtil) FindOutValesStr(slice1 []string, slice2 []string) []string { // 创建一个map,用于存储slice2中出现的所有元素 m := make(map[string]bool) for _, i := range slice2 { m[i] = true } // 创建一个空的切片,用于存储slice1中不同于slice2的元素 var result []string for _, i := range slice1 { if !m[i] { result = append(result, i) } } // 返回slice2独有的元素组成的切片 return result } // 模糊搜索 func (s *toolSliceUtil) FilterSlice(slice []map[string]interface{}, key string, value interface{}) []map[string]interface{} { result := make([]map[string]interface{}, 0) for _, item := range slice { if val, ok := item[key]; ok && strings.Contains(fmt.Sprintf("%v", val), fmt.Sprintf("%v", value)) { result = append(result, item) } } return result } /* 参数 slice 是一个 []map[string]interface{} 类型的切片,每个 map 中包含一条数据记录。 参数 key 和 name 都是字符串类型,分别表示按照哪个键进行分组和新生成的记录的名称。 返回值是一个 []map[string]interface{} 类型的切片,其中每个 map 表示一组已经分好组的数据记录。 */ // GroupByKey 将[]map[string]interface{}按某个字段分组 func (s *toolSliceUtil) GroupByKey(slice []map[string]interface{}, key string, name string) []map[string]interface{} { // 创建一个 map[interface{}][]interface{} 类型的变量 transformedData,用于存储已经分组后的数据。 transformedData := make(map[interface{}][]interface{}) // 遍历输入的每个 map[string]interface{} 类型的数据记录 d,在 transformedData 中找到对应的键 k,将其添加到分组后的列表中。 for _, d := range slice { k := d[key] if data, ok := transformedData[k]; ok { transformedData[k] = append(data, d) } else { transformedData[k] = []interface{}{d} } } // 创建一个 []map[string]interface{} 类型的切片 result,遍历 transformedData map 中的所有键值对, // 并将其转换为新的 map[string]interface{} 类型的数据记录,并添加到 result 切片中。 result := make([]map[string]interface{}, 0, len(transformedData)) for k, v := range transformedData { m := map[string]interface{}{ key: k, name: v, } result = append(result, m) } // 返回 result 切片即可。 return result } /* 如果某个元素的 key 对应的不是 int 类型,则返回一个空的 []int 类型的切片。 */ //MapListKeyToSliceInt 函数从输入的 []map[string]interface{} 类型的切片中提取指定 key 对应的 int 类型数值,并返回一个 []int 类型的切片。 func (s *toolSliceUtil) MapListKeyToSliceInt(list []map[string]interface{}, key string) []int { // 创建一个 []int 类型的切片 result,用于存储提取出来的 int 数值。 result := make([]int, len(list)) // 遍历输入的每个 map[string]interface{} 类型的数据记录 m,在其中找到 key 对应的值 v, // 如果 v 是 int 类型,则将其赋值给 result 切片对应的位置;否则,返回一个空的 []int 类型的切片。 for i, m := range list { if v, ok := m[key]; ok { if num, ok := v.(int); ok { result[i] = num } else { return []int{} } } else { return []int{} } } // 返回 result 切片即可。 return result } func (s *toolSliceUtil) MapListKeyToSliceStr(list []map[string]interface{}, key string) []string { // 创建一个 []int 类型的切片 result,用于存储提取出来的 int 数值。 result := make([]string, len(list)) // 遍历输入的每个 map[string]interface{} 类型的数据记录 m,在其中找到 key 对应的值 v, // 如果 v 是 int 类型,则将其赋值给 result 切片对应的位置;否则,返回一个空的 []int 类型的切片。 for i, m := range list { if v, ok := m[key]; ok { if num, ok := v.(string); ok { result[i] = num } else { return []string{} } } else { return []string{} } } // 返回 result 切片即可。 return result } // 移动第一位 func (s *toolSliceUtil) MoveToFirst(slice []map[string]interface{}, key string, value interface{}) { for i, item := range slice { if val, ok := item[key]; ok && val == value { // 将匹配到的元素移动到切片的第一位 copy(slice[1:i+1], slice[:i]) slice[0] = item break } } } // 分页 func (s *toolSliceUtil) Paginate(data []map[string]interface{}, pageNumber, itemsPerPage int) []map[string]interface{} { if len(data) == 0 { return nil } // 计算切片的总页数 totalPages := (len(data) + itemsPerPage - 1) / itemsPerPage // 确保页码在有效范围内 if pageNumber < 1 { pageNumber = 1 } else if pageNumber > totalPages { pageNumber = totalPages } // 计算切片的起始索引和结束索引 startIndex := (pageNumber - 1) * itemsPerPage endIndex := startIndex + itemsPerPage // 防止结束索引越界 if endIndex > len(data) { endIndex = len(data) } // 返回分页数据 return data[startIndex:endIndex] } // 删除指定key func (s *toolSliceUtil) RemoveKeysFromMaps(slice []map[string]interface{}, keysToRemove []string) []map[string]interface{} { // 创建新的切片用于存储删除键后的结果 updatedSlice := make([]map[string]interface{}, 0) // 遍历原始切片 for _, item := range slice { // 创建新的 map 用于存储删除键后的元素 updatedItem := make(map[string]interface{}) // 复制原始 map 的键值对到新的 map for k, v := range item { // 检查当前键是否需要删除 if !contains(keysToRemove, k) { updatedItem[k] = v } } // 将删除键后的元素添加到新的切片 updatedSlice = append(updatedSlice, updatedItem) } return updatedSlice } func contains(slice []string, key string) bool { for _, v := range slice { if v == key { return true } } return false } func (s *toolSliceUtil) UniqueInt(slice []int) []int { seen := make(map[int]bool) result := []int{} for _, num := range slice { if !seen[num] { result = append(result, num) seen[num] = true } } return result } func (s *toolSliceUtil) UniqueString(slice []string) []string { seen := make(map[string]bool) result := []string{} for _, num := range slice { if !seen[num] { result = append(result, num) seen[num] = true } } return result } type SortField struct { Key string IsAsc bool } func (s *toolSliceUtil) SortByKey(slice []map[string]interface{}, fields []SortField) { // 调用 sort.SliceStable 函数对 slice 进行排序,并提供一个函数作为比较器。 sort.SliceStable(slice, func(i, j int) bool { for _, field := range fields { key := field.Key isAsc := field.IsAsc switch v1 := slice[i][key].(type) { case int: v2, _ := slice[j][key].(int) if v1 != v2 { if isAsc { return v1 < v2 } else { return v1 > v2 } } case int32: v2, _ := slice[j][key].(int32) if v1 != v2 { if isAsc { return v1 < v2 } else { return v1 > v2 } } case int64: v2, _ := slice[j][key].(int64) if v1 != v2 { if isAsc { return v1 < v2 } else { return v1 > v2 } } case float32: v2, _ := slice[j][key].(float32) if v1 != v2 { if isAsc { return v1 < v2 } else { return v1 > v2 } } case float64: v2, _ := slice[j][key].(float64) if v1 != v2 { if isAsc { return v1 < v2 } else { return v1 > v2 } } case string: v2, _ := slice[j][key].(string) if v1 != v2 { if isAsc { return v1 < v2 } else { return v1 > v2 } } default: fmt.Printf("unsupported type for key '%s': %s\n", key, reflect.TypeOf(v1)) return false } } return false }) } func compareJsonNumbers(a, b json.Number) bool { af, aErr := a.Float64() bf, bErr := b.Float64() if aErr != nil || bErr != nil { ai, aErr := a.Int64() bi, bErr := b.Int64() if aErr != nil || bErr != nil { fmt.Println("unsupported json.Number format") return false } return ai < bi } return af < bf } // StringToSliceInt 将字符串解析为Int切片类型 func (s *toolSliceUtil) StringToSliceInt(str string) []int { var slice []int err := json.Unmarshal([]byte(str), &slice) if err != nil { return []int{} } return slice } func (s *toolSliceUtil) StringToSliceStr(str string) []string { var slice []string err := json.Unmarshal([]byte(str), &slice) if err != nil { return []string{} } return slice } ~~~