求笛卡尔积

Q: 求 ["a", "b"], ["x", "y"], [1, 2, 3] 的迪卡尔积。

1. python 版本

#!/usr/bin/env python
#-*-coding:utf-8-*-

import itertools

a = ["a", "b"]
b = ["x", "y"]
c = [1, 2, 3]

# 计算笛卡尔积
# Param : 以单个集合(数组)作为参数,可以支持变长参数,即多个集合。
# Return: 返回组合的个数及对应的数组集合
def combination(*array):
  # 错误处理, 如果当只有一个集合进行计算,则抛出异常
  if len(array) < 2:
    raise ValueError("至少有2个集合")
  if len(array) > 12:
    print("数据量较大,生成集合耗时较长, 请耐心等待")

  count = 0
  items = []
  for item in itertools.product(*array):
    count += 1
    print item
    items.append(item)
  return (count, items)

if __name__ == '__main__' :
  print "笛卡尔积:"

  # 如果有多少集合数据,可以',' 分隔作为参数传递给函数combination(), 如combination(a1, a2, a3, a4, ...)
  # count, items = combination(a, b, c, a, b, c, a, b, c, a, b, c)
  # count, items = combination(a)
  count, items = combination(a, b, c)
  print "此笛卡尔积组合为: ", items
  print "共有 %d 个组合" % (count)

2. golang 版本

package main

import (
    "errors"
    "fmt"
)

// 递归下一个 index
func NextIndex(idx []int, lenArr []int) {
    j := len(idx) - 1
    for ; j >= 0; j-- {
        fmt.Println("debug========:", j, idx)
        idx[j]++
        fmt.Println("debug========:", j, idx)
        if j == 0 || idx[j] < lenArr[j] {
            return
        }
        // 首次返回0下标
        idx[j] = 0
    }
}

func Combination(arr ...[]string) (count int, arrList [][]string, err error) {
    // 错误处理, 少于2个集合则错误返回。
    if len(arr) < 2 {
        fmt.Println("至少有2个集合")
        errors.New("至少有2个集合")
        count = -1
        return
    }

    // 将每一个集合的长度记录下来, 并存放在数组中
    lenArray := []int{}
    for index, _ := range arr {
        lenArray = append(lenArray, len(arr[index]))
    }

    // 构造索引数组, 并初始化[], 值为0
    idx := make([]int, len(arr))

    // 索引数组中索引小于集合长度进行循环, 从右往左依次增加下标idx数值,实现遍历。
    for ; idx[0] < lenArray[0]; NextIndex(idx, lenArray) {
        var r []string

        for j, k := range idx {
            fmt.Println("debug2======", r, j, k, idx)
            // 依次合并相邻集合,最终所有元素存放在r数组中
            r = append(r, arr[j][k])
        }
        fmt.Println(r)
        arrList = append(arrList, r)
    }
    count = len(arrList)
    return
}

func main() {
    arr1 := []string{"a", "b"}
    arr2 := []string{"x", "y"}
    arr3 := []string{"1", "2", "3"}

    // Combination(arr1, arr2, arr3, arr1)
    count, arrList, err := Combination(arr1, arr2, arr3, arr1)
    // count, arrList, err := Combination(arr1)
    if err == nil {
        fmt.Printf("笛卡尔积组合为:%s, 共有:%d 个组合\n", arrList, count)
    }
}