Skip to content
鼓励作者:欢迎打赏犒劳

数据处理工具类

对标java8的stream!!!!

工具类

go
package data_deal_tool

import (
	"cmp"
	"slices"

	"github.com/samber/lo"
)

// ==================================================================
// 工具类:List 过滤
// ==================================================================

// FilterFirst 通用函数:在切片中查找第一个满足条件的元素
// 返回 (元素, 是否找到)
func FilterFirst[T any](slice []T, predicate func(T) bool) (T, bool) {
	var zero T
	for _, item := range slice {
		if predicate(item) {
			return item, true
		}
	}
	return zero, false
}

// Filter 通用函数:返回切片中所有满足 predicate 条件的元素
func Filter[T any](slice []T, predicate func(T) bool) []T {
	var result []T
	for _, item := range slice {
		if predicate(item) {
			result = append(result, item)
		}
	}
	return result
}

// ==================================================================
// 工具类:List 转 Map
// ==================================================================

// ListToMapByKey 将 []T 转为 map[K]T,key 由 keySelector 生成 ,如果 key 重复,默认是“后面的元素覆盖前面的”。
func ListToMapByKey[T any, K comparable](items []T, keySelector func(T) K) map[K]T {
	return lo.SliceToMap(items, func(item T) (K, T) {
		return keySelector(item), item
	})
}

// ListToGroupedMap 将 []T 转为 map[K][]T,按 key 分组
func ListToGroupedMap[T any, K comparable](items []T, keySelector func(T) K) map[K][]T {
	return lo.GroupBy(items, keySelector)
}

// ListToMapByKey2Key 将 []T 转为 map[K]V  字段对应字段  ,如果 key 重复,默认是“后面的元素覆盖前面的”。
func ListToMapByKey2Key[T any, K comparable, V any](items []T, keySelector func(T) K, valueSelector func(T) V) map[K]V {
	m := make(map[K]V, len(items))
	for _, item := range items {
		key := keySelector(item)
		value := valueSelector(item)
		m[key] = value
	}
	return m
}

// ==================================================================
// 工具类:List 转 List
// ==================================================================

// Map 将切片中的每个元素通过 mapper 函数映射为另一种类型  对应 Java: .stream().map(...).collect(...)
func Map[T any, R any](slice []T, mapper func(T) R) []R {
	result := make([]R, len(slice))
	for i, item := range slice {
		result[i] = mapper(item)
	}
	return result
}

// MapAndFilter 先过滤,再映射,返回目标类型的切片 集合对象提取单个字段数组 将 []T  转为 []R
func MapAndFilter[T any, R any](slice []T, predicate func(T) bool, mapper func(T) R) []R {
	result := make([]R, 0, len(slice)) // 预分配容量
	for _, item := range slice {
		if predicate(item) {
			result = append(result, mapper(item))
		}
	}
	return result
}

// FlatMap 将每个元素映射成一个切片,然后展开合并为一个切片  示例:[][]int 展平 或 多对多映射
func FlatMap[T any, R any](slice []T, mapper func(T) []R) []R {
	var result []R
	for _, item := range slice {
		result = append(result, mapper(item)...)
	}
	return result
}

// Chunk 将切片分成大小为 size 的子切片
func Chunk[T any](slice []T, size int) [][]T {
	return lo.Chunk(slice, size)
}

// Partition 将切片分为两个列表:满足条件 vs 不满足条件
func Partition[T any](slice []T, predicate func(T) bool) ([]T, []T) {
	var yes []T
	var no []T
	for _, item := range slice {
		if predicate(item) {
			yes = append(yes, item)
		} else {
			no = append(no, item)
		}
	}
	return yes, no
}

// ==================================================================
// 工具类:聚合操作
// ==================================================================

// Reduce 聚合所有元素为单个值,类似 foldLeft  对应 Java: .stream().reduce(...) 例如求和、拼接字符串等。
func Reduce[T any, R any](slice []T, initial R, accumulator func(R, T) R) R {
	result := initial
	for _, item := range slice {
		result = accumulator(result, item)
	}
	return result
}

// ==================================================================
// 工具类:条件判断
// ==================================================================

// AnyMatch 是否存在至少一个元素满足条件  对应 Java: .anyMatch()
func AnyMatch[T any](slice []T, predicate func(T) bool) bool {
	for _, item := range slice {
		if predicate(item) {
			return true
		}
	}
	return false
}

// AllMatch 是否所有元素都满足条件   对应 Java: .allMatch()
func AllMatch[T any](slice []T, predicate func(T) bool) bool {
	for _, item := range slice {
		if !predicate(item) {
			return false
		}
	}
	return true
}

// NoneMatch 是否没有元素满足条件   对应 Java:  .noneMatch()
func NoneMatch[T any](slice []T, predicate func(T) bool) bool {
	return !AnyMatch(slice, predicate)
}

// ==================================================================
// 工具类:去重
// ==================================================================

// Distinct 去除重复元素(基于 comparable 类型)  对应 Java: .distinct()
func Distinct[T comparable](slice []T) []T {
	seen := make(map[T]struct{}, len(slice))
	var result []T
	for _, item := range slice {
		if _, exists := seen[item]; !exists {
			seen[item] = struct{}{}
			result = append(result, item)
		}
	}
	return result
}

// DistinctBy 根据 keySelector 去重
func DistinctBy[T any, K comparable](slice []T, keySelector func(T) K) []T {
	seen := make(map[K]struct{})
	var result []T
	for _, item := range slice {
		key := keySelector(item)
		if _, exists := seen[key]; !exists {
			seen[key] = struct{}{}
			result = append(result, item)
		}
	}
	return result
}

// ==================================================================
// 工具类:排序
// ==================================================================

// SortBy 对切片按 keySelector 提取的键进行升序排序(修改原切片)
func SortBy[T any, K Ordered](slice []T, keySelector func(T) K) {
	slices.SortFunc(slice, func(a, b T) int {
		return cmp.Compare(keySelector(a), keySelector(b))
	})
}

// Ordered 是可比较的基本类型的约束
type Ordered interface {
	~int | ~int8 | ~int16 | ~int32 | ~int64 |
		~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 |
		~float32 | ~float64 |
		~string
}

测试用例

go
package data_deal_tool

import (
	"fmt"
	"testing"
)

// 示例结构体用于测试
type User struct {
	ID     int
	Name   string
	Age    int
	City   string
	Active bool
}

func TestAllDataDealToolFunctions(t *testing.T) {
	users := []User{
		{ID: 1, Name: "Alice", Age: 25, City: "Beijing", Active: true},
		{ID: 2, Name: "Bob", Age: 30, City: "Shanghai", Active: true},
		{ID: 3, Name: "Charlie", Age: 35, City: "Beijing", Active: false},
		{ID: 4, Name: "David", Age: 25, City: "Guangzhou", Active: true},
		{ID: 5, Name: "Eve", Age: 30, City: "Shanghai", Active: true},
		{ID: 6, Name: "Frank", Age: 40, City: "Beijing", Active: false},
	}

	fmt.Println("=== 1. FilterFirst: 查找第一个北京用户 ===")
	if user, found := FilterFirst(users, func(u User) bool {
		return u.City == "Beijing"
	}); found {
		fmt.Printf("找到第一位北京用户: %+v\n", user)
	} else {
		fmt.Println("未找到北京用户")
	}

	fmt.Println("\n=== 2. Filter: 过滤所有活跃用户 ===")
	activeUsers := Filter(users, func(u User) bool {
		return u.Active
	})
	fmt.Printf("活跃用户: %+v\n", activeUsers)

	fmt.Println("\n=== 3. ListToMapByKey: 按 ID 构建 map[ID]User ===")
	userMap := ListToMapByKey(users, func(u User) int {
		return u.ID
	})
	fmt.Printf("用户ID映射: %+v\n", userMap)

	fmt.Println("\n=== 4. ListToGroupedMap: 按城市分组 ===")
	groupedByCity := ListToGroupedMap(users, func(u User) string {
		return u.City
	})
	for city, group := range groupedByCity {
		fmt.Printf("城市 %s: %+v\n", city, group)
	}

	fmt.Println("\n=== 5. ListToMapByKey2Key: 构建 map[ID]Name ===")
	idToName := ListToMapByKey2Key(users, func(u User) int {
		return u.ID
	}, func(u User) string {
		return u.Name
	})
	fmt.Printf("ID -> Name 映射: %+v\n", idToName)

	fmt.Println("\n=== 6. Map: 提取所有用户名字 ===")
	names := Map(users, func(u User) string {
		return u.Name
	})
	fmt.Printf("所有用户名: %v\n", names)

	fmt.Println("\n=== 7. MapAndFilter: 提取活跃用户的年龄 ===")
	activeAges := MapAndFilter(users, func(u User) bool {
		return u.Active
	}, func(u User) int {
		return u.Age
	})
	fmt.Printf("活跃用户年龄: %v\n", activeAges)

	fmt.Println("\n=== 8. FlatMap: 每个用户生成其名字重复2次的切片,然后展平 ===")
	repeatedNames := FlatMap(users, func(u User) []string {
		return []string{u.Name, u.Name}
	})
	fmt.Printf("名字重复展平: %v\n", repeatedNames)

	fmt.Println("\n=== 9. Chunk: 每2个用户分一块 ===")
	chunks := Chunk(users, 2)
	for i, chunk := range chunks {
		fmt.Printf("块 %d: %+v\n", i+1, chunk)
	}

	fmt.Println("\n=== 10. Partition: 分割为活跃和非活跃用户 ===")
	active, inactive := Partition(users, func(u User) bool {
		return u.Active
	})
	fmt.Printf("活跃用户: %+v\n", active)
	fmt.Printf("非活跃用户: %+v\n", inactive)

	fmt.Println("\n=== 11. Reduce: 计算所有用户年龄总和 ===")
	totalAge := Reduce(users, 0, func(sum int, u User) int {
		return sum + u.Age
	})
	fmt.Printf("用户年龄总和: %d\n", totalAge)

	fmt.Println("\n=== 12. AnyMatch: 是否有用户年龄 > 35? ===")
	hasOld := AnyMatch(users, func(u User) bool {
		return u.Age > 35
	})
	fmt.Printf("是否有年龄 > 35 的用户: %t\n", hasOld)

	fmt.Println("\n=== 13. AllMatch: 是否所有用户年龄 >= 25? ===")
	allAdult := AllMatch(users, func(u User) bool {
		return u.Age >= 25
	})
	fmt.Printf("是否所有用户年龄 >= 25: %t\n", allAdult)

	fmt.Println("\n=== 14. NoneMatch: 是否没有用户叫 'Zoe'? ===")
	noZoe := NoneMatch(users, func(u User) bool {
		return u.Name == "Zoe"
	})
	fmt.Printf("是否没有叫 'Zoe' 的用户: %t\n", noZoe)

	fmt.Println("\n=== 15. Distinct: 去重名字(假设名字有重复)===")
	duplicatedNames := []string{"Alice", "Bob", "Alice", "David", "Bob"}
	uniqueNames := Distinct(duplicatedNames)
	fmt.Printf("去重后名字: %v\n", uniqueNames)

	fmt.Println("\n=== 16. DistinctBy: 按年龄去重(保留首次出现)===")
	uniqueByAge := DistinctBy(users, func(u User) int {
		return u.Age
	})
	fmt.Printf("按年龄去重后的用户: %+v\n", uniqueByAge)

	fmt.Println("\n=== 17. SortBy: 按年龄升序排序 ===")
	sortedByAge := make([]User, len(users))
	copy(sortedByAge, users)
	SortBy(sortedByAge, func(u User) int {
		return u.Age
	})
	fmt.Printf("按年龄排序: %+v\n", sortedByAge)

	fmt.Println("\n=== 18. SortBy: 按名字排序 ===")
	sortedByName := make([]User, len(users))
	copy(sortedByName, users)
	SortBy(sortedByName, func(u User) string {
		return u.Name
	})
	fmt.Printf("按名字排序: %+v\n", sortedByName)
}

结果:

text
=== 1. FilterFirst: 查找第一个北京用户 ===
找到第一位北京用户: {ID:1 Name:Alice Age:25 City:Beijing Active:true}

=== 2. Filter: 过滤所有活跃用户 ===
活跃用户: [{ID:1 Name:Alice Age:25 City:Beijing Active:true} {ID:2 Name:Bob Age:30 City:Shanghai Active:true} {ID:4 Name:David Age:25 City:Guangzhou Active:true} {ID:5 Name:Eve Age:30 City:Shanghai Active:true}]

=== 3. ListToMapByKey: 按 ID 构建 map[ID]User ===
用户ID映射: map[1:{ID:1 Name:Alice Age:25 City:Beijing Active:true} 2:{ID:2 Name:Bob Age:30 City:Shanghai Active:true} 3:{ID:3 Name:Charlie Age:35 City:Beijing Active:false} 4:{ID:4 Name:David Age:25 City:Guangzhou Active:true} 5:{ID:5 Name:Eve Age:30 City:Shanghai Active:true} 6:{ID:6 Name:Frank Age:40 City:Beijing Active:false}]

=== 4. ListToGroupedMap: 按城市分组 ===
城市 Beijing: [{ID:1 Name:Alice Age:25 City:Beijing Active:true} {ID:3 Name:Charlie Age:35 City:Beijing Active:false} {ID:6 Name:Frank Age:40 City:Beijing Active:false}]
城市 Shanghai: [{ID:2 Name:Bob Age:30 City:Shanghai Active:true} {ID:5 Name:Eve Age:30 City:Shanghai Active:true}]
城市 Guangzhou: [{ID:4 Name:David Age:25 City:Guangzhou Active:true}]

=== 5. ListToMapByKey2Key: 构建 map[ID]Name ===
ID -> Name 映射: map[1:Alice 2:Bob 3:Charlie 4:David 5:Eve 6:Frank]

=== 6. Map: 提取所有用户名字 ===
所有用户名: [Alice Bob Charlie David Eve Frank]

=== 7. MapAndFilter: 提取活跃用户的年龄 ===
活跃用户年龄: [25 30 25 30]

=== 8. FlatMap: 每个用户生成其名字重复2次的切片,然后展平 ===
名字重复展平: [Alice Alice Bob Bob Charlie Charlie David David Eve Eve Frank Frank]

=== 9. Chunk: 每2个用户分一块 ===
块 1: [{ID:1 Name:Alice Age:25 City:Beijing Active:true} {ID:2 Name:Bob Age:30 City:Shanghai Active:true}]
块 2: [{ID:3 Name:Charlie Age:35 City:Beijing Active:false} {ID:4 Name:David Age:25 City:Guangzhou Active:true}]
块 3: [{ID:5 Name:Eve Age:30 City:Shanghai Active:true} {ID:6 Name:Frank Age:40 City:Beijing Active:false}]

=== 10. Partition: 分割为活跃和非活跃用户 ===
活跃用户: [{ID:1 Name:Alice Age:25 City:Beijing Active:true} {ID:2 Name:Bob Age:30 City:Shanghai Active:true} {ID:4 Name:David Age:25 City:Guangzhou Active:true} {ID:5 Name:Eve Age:30 City:Shanghai Active:true}]
非活跃用户: [{ID:3 Name:Charlie Age:35 City:Beijing Active:false} {ID:6 Name:Frank Age:40 City:Beijing Active:false}]

=== 11. Reduce: 计算所有用户年龄总和 ===
用户年龄总和: 185

=== 12. AnyMatch: 是否有用户年龄 > 35? ===
是否有年龄 > 35 的用户: true

=== 13. AllMatch: 是否所有用户年龄 >= 25? ===
是否所有用户年龄 >= 25: true

=== 14. NoneMatch: 是否没有用户叫 'Zoe'? ===
是否没有叫 'Zoe' 的用户: true

=== 15. Distinct: 去重名字(假设名字有重复)===
去重后名字: [Alice Bob David]

=== 16. DistinctBy: 按年龄去重(保留首次出现)===
按年龄去重后的用户: [{ID:1 Name:Alice Age:25 City:Beijing Active:true} {ID:2 Name:Bob Age:30 City:Shanghai Active:true} {ID:3 Name:Charlie Age:35 City:Beijing Active:false} {ID:6 Name:Frank Age:40 City:Beijing Active:false}]

=== 17. SortBy: 按年龄升序排序 ===
按年龄排序: [{ID:1 Name:Alice Age:25 City:Beijing Active:true} {ID:4 Name:David Age:25 City:Guangzhou Active:true} {ID:2 Name:Bob Age:30 City:Shanghai Active:true} {ID:5 Name:Eve Age:30 City:Shanghai Active:true} {ID:3 Name:Charlie Age:35 City:Beijing Active:false} {ID:6 Name:Frank Age:40 City:Beijing Active:false}]

=== 18. SortBy: 按名字排序 ===
按名字排序: [{ID:1 Name:Alice Age:25 City:Beijing Active:true} {ID:2 Name:Bob Age:30 City:Shanghai Active:true} {ID:3 Name:Charlie Age:35 City:Beijing Active:false} {ID:4 Name:David Age:25 City:Guangzhou Active:true} {ID:5 Name:Eve Age:30 City:Shanghai Active:true} {ID:6 Name:Frank Age:40 City:Beijing Active:false}]

如有转载或 CV 的请标注本站原文地址