You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

99 lines
2.0 KiB

package collect
// CartesianCount 笛卡尔积组合数
func CartesianCount[T any](sets ...[]T) (total int) {
total = 1
for _, set := range sets {
total *= len(set)
}
return
}
// CartesianProduct 笛卡尔积(返回所有可能的组合)
// 输入: [][]T 类型的二维切片
// 输出: []T 类型的切片组成的切片
func CartesianProduct[T any](sets ...[]T) [][]T {
if len(sets) == 0 {
return [][]T{{}}
}
// 初始化为第一个集合的所有单元素组合
result := make([][]T, len(sets[0]))
for i, v := range sets[0] {
result[i] = []T{v}
}
// 依次处理后续每一组
for _, set := range sets[1:] {
if len(set) == 0 {
return [][]T{}
}
newResult := make([][]T, 0, len(result)*len(set))
for _, prev := range result {
for _, curr := range set {
// 预分配空间,避免频繁扩容
combined := make([]T, 0, len(prev)+1)
combined = append(combined, prev...)
combined = append(combined, curr)
newResult = append(newResult, combined)
}
}
result = newResult
}
return result
}
// CartesianYield 生成笛卡尔积的所有组合,并为每个组合调用回调函数
// callback: func(comb []T) bool - 处理当前组合,返回 true 继续生成,返回 false 停止
// return: 生成的组合总数
func CartesianYield[T any](sets [][]T, callback func([]T) bool) int {
if len(sets) == 0 {
return 0
}
// 检查是否有空集
for _, s := range sets {
if len(s) == 0 {
return 0
}
}
// 初始化索引计数器
indices := make([]int, len(sets))
comb := make([]T, len(sets)) // 复用缓冲区,避免每次分配
count := 0
for {
// 构建当前组合
for i, idx := range indices {
comb[i] = sets[i][idx]
}
// 调用回调
count++
if !callback(comb) {
break // 停止生成
}
// 递增索引,像计数器一样
i := len(indices) - 1
for i >= 0 {
indices[i]++
if indices[i] < len(sets[i]) {
break
}
indices[i] = 0
i--
}
if i < 0 {
break // 所有组合已生成
}
}
return count
}