Excel - 生成每行三组数字的笛卡尔积

时间:2017-03-12 16:29:27

标签: excel excel-vba excel-formula cartesian-product vba

我在一行中的数据格式如下:

设置1(仅包含一个数字)|设置2(在唯一单元格中包含1-6个数字)|设置3(在独特单元格中包含1-6 |

示例:[1] | [1] [2] [3] | [1] [5]

输出:1 1 1,1 1 5,1 2 1,1 2 5,1 3 1,1 3 5

2 个答案:

答案 0 :(得分:1)

这是一个VBA函数,可以处理3个数字集的特殊情况:

Function CartesianProduct(nums1 As Range, nums2 As Range, nums3 As Range) As Variant
    Dim n As Long 'number of products
    Dim i As Long, j As Long, k As Long, r As Long
    Dim products As Variant

    n = nums1.Cells.Count * nums2.Cells.Count * nums3.Cells.Count
    ReDim products(1 To n, 1 To 3)
    For i = 1 To nums1.Cells.Count
        For j = 1 To nums2.Cells.Count
            For k = 1 To nums3.Cells.Count
                r = r + 1 'current row
                products(r, 1) = nums1.Cells(i)
                products(r, 2) = nums2.Cells(j)
                products(r, 3) = nums3.Cells(k)
            Next k
        Next j
    Next i
    CartesianProduct = products
End Function

这可以从另一个VBA函数或子函数调用,或直接用作工作表中的数组公式:

enter image description here

在上面的屏幕截图中我选择了范围A3:C8(需要提前确定其大小)输入公式

=CartesianProduct(A1,B1:D1,E1:F1)

然后通过Ctrl+Shift+Enter输入它作为数组公式接受它。

一旦你超越了三组,事情会变得有点棘手,因为你不能在循环方法的必要级别中硬连线,而是可能使用递归方法,这就像这个答案:{{3} }

答案 1 :(得分:0)

这是一个做任意维度的笛卡尔积的函数 - 每个维度的值必须垂直列出,一个维度可能有多个列(见下面的例子):

Function CartesianProduct(ParamArray range() As Variant) As Variant
    Dim n As Long 'number of products
    Dim total_dimensions As Long, i As Long, num_dim As Long, num_col As Long, max_cols As Long
    Dim dim_sizes As Variant
    Dim dim_counters As Variant
    Dim products As Variant
    
    ReDim dim_sizes(LBound(range) To UBound(range))
    ReDim dim_counters(LBound(range) To UBound(range))
    n = 1
    max_cols = 0
    For i = LBound(range) To UBound(range)
        dim_sizes(i) = range(i).Rows.Count
        max_cols = max_cols + range(i).Columns.Count
        n = n * dim_sizes(i)
        dim_counters(i) = 1
    Next
    ReDim products(1 To n, 1 To max_cols)
    For i = 1 To n
        carry_one = True
        num_col = max_cols
        For num_dim = UBound(range) To LBound(range) Step -1
            For j = range(num_dim).Columns.Count To 1 Step -1
                products(i, num_col) = range(num_dim).Cells(dim_counters(num_dim), j)
                num_col = num_col - 1
            Next j
            If carry_one = True Then
                dim_counters(num_dim) = dim_counters(num_dim) + 1
                If dim_counters(num_dim) > dim_sizes(num_dim) Then
                    dim_counters(num_dim) = 1
                    carry_one = True
                Else
                    carry_one = False
                End If
            End If
        Next num_dim
    Next i
    CartesianProduct = products
End Function

示例(注意第一维有两列): Excel Cartesian Product