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

Excel-生成每行三组数字的笛卡尔积,excel,excel-formula,cartesian-product,vba,Excel,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这里有一个VBA函数,可以处理3个数字集的特殊情况: Function CartesianProduct(nums1 As Range, nums2 As Range, nums3 As Range) As Variant Dim

我有一行数据,格式如下:

集合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这里有一个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函数或子函数调用,或直接用作工作表中的数组公式:

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

=CartesianProduct(A1,B1:D1,E1:F1)
然后通过使用
Ctrl+Shift+Enter
输入它,将其作为数组公式接受


一旦超过三个集合,事情就会变得有点棘手,因为对于循环方法,你不能在必要的层次上硬连线,而可能会使用递归方法,类似于下面的回答:

这是一个函数,可以对任意数量的维度进行笛卡尔积-每个维度的值必须是li垂直放置时,一个维度可能有多个列(请参见下面的示例):

示例(请注意,第一个标注有两列):

请解释所需的输出。即使您使用的是“排列”一词,我怀疑您可能是指其他内容。对于上面的示例:[1]|[1][2][3]|[1][5]输出:1 11,1 15,1 2 1,1 2 5,1 3 1,1 3 5我有一种感觉,我可能是指组合。实际上,我怀疑你指的是更像笛卡尔积的东西,而不是排列或组合。如果你编辑你的问题以显示预期的输出,那会有所帮助。编辑。我没听说过这个!谢谢你帮助我我回答了这个问题。谢谢你,约翰。效果非常好!感谢你的帮助。学习新东西总是很棒的。
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