【问题标题】:Replicate Google Sheets {array1; array2} function in Microsoft Excel as user defined function复制 Google 表格 {array1; array2} 函数在 Microsoft Excel 中作为用户定义函数
【发布时间】:2021-10-09 18:50:08
【问题描述】:

在 Google 表格中,我可以使用 ={range1;range2;...} 表示法将多个范围附加到一个范围中,作为公式的一部分。在 Excel 中,此功能似乎不能作为公式使用。我想创建一个用户定义的函数来允许我在 Excel 中附加范围。

理想情况下,该功能应具有与 Google 表格版本类似的简单性。 我附上了带有基本用例的link to a public Google Sheets 文档,以防万一。

我试过Tom's answer,但它给出了一个错误(见example photo)。

谢谢!

【问题讨论】:

  • @ScottCraner =CHOOSE({1,2},range1,range2) 似乎正在创建一个 3x3 数组,其中第一列来自第一个范围,第二列来自第二个范围,第三列填充 #N/A 错误。有没有办法将我的第二个范围的行附加到我的第一个范围的行上?如果我有两个 3x3 源数组,我希望得到一个 3x6 结果数组。谢谢!
  • 感谢您的提问。我认为我的回答应该做你想做的。实际上,我不知道您可以使用 Google 表格中的分号执行您所显示的操作。很酷。

标签: excel vba append user-defined-functions


【解决方案1】:

这是一个通用的 UDF,用于堆叠相同列数的范围:

Function vStack(ParamArray rng() As Variant) As Variant
    If TypeName(rng(1)) <> "Range" Then Exit Function
    Dim otarr() As Variant
    ReDim otarr(1 To 100000, 1 To rng(1).Columns.Count)
    
    Dim z As Long
    z = 1
    
    Dim i As Long
    For i = LBound(rng) To UBound(rng)
        If TypeName(rng(i)) <> "Range" Then Exit Function
        If i > LBound(rng) Then
            If rng(i).Columns.Count <> rng(i - 1).Columns.Count Then Exit Function
        End If
        Dim rngarr As Variant
        rngarr = Intersect(rng(i), rng(i).Parent.UsedRange)
        Dim j As Long
        For j = LBound(rngarr, 1) To UBound(rngarr, 1)
            Dim k As Long
            For k = LBound(rngarr, 2) To UBound(rngarr, 2)
                otarr(z, k) = rngarr(j, k)
            Next k
            z = z + 1
        Next j
    Next i
    
    Dim nArray() As Variant
    ReDim nArray(1 To z - 1, 1 To UBound(otarr, 2))
    
    For i = 1 To z - 1
        For j = 1 To UBound(otarr, 2)
            nArray(i, j) = otarr(i, j)
        Next j
    Next i
    
    vStack = nArray

End Function

请注意,我将初始数组限制为 100,000 行。如果这还不够,您可以将其提升到您想要的任何程度,但也要考虑“我是否将 Excel 视为数据库?”。如果答案是肯定的,那么是时候切换到实际的参考数据库了。

然后可以在公式中使用它:

=FILTER(vStack(A:C,F:H),vStack(A:A,F:F)="Apples")


编辑以包含适用于数组的版本,即:=vstack({1;2;3},{4;5;6})

Function vStack(ParamArray rng() As Variant) As Variant
    Dim otarr() As Variant
    If TypeName(rng(1)) = "Range" Then
        ReDim otarr(1 To 100000, 1 To rng(1).Columns.Count)
    Else
        ReDim otarr(1 To 100000, 1 To UBound(rng(1), 2))
    End If
        
    
    
    Dim z As Long
    z = 1
    
    Dim i As Long
    For i = LBound(rng) To UBound(rng)
        
        If i > LBound(rng) Then
            If TypeName(rng(i)) = "Range" Then
                If rng(i).Columns.Count <> UBound(otarr, 2) Then Exit Function
            Else
                If UBound(rng(i), 2) <> UBound(otarr, 2) Then Exit Function
            End If
        End If
        Dim rngarr As Variant
        If TypeName(rng(i)) = "Range" Then
            rngarr = Intersect(rng(i), rng(i).Parent.UsedRange)
        Else
            rngarr = rng(i)
        End If

        Dim j As Long
        For j = LBound(rngarr, 1) To UBound(rngarr, 1)
            Dim k As Long
            For k = LBound(rngarr, 2) To UBound(rngarr, 2)
                otarr(z, k) = rngarr(j, k)
            Next k
            z = z + 1
        Next j
    Next i
    
    Dim nArray() As Variant
    ReDim nArray(1 To z - 1, 1 To UBound(otarr, 2))
    
    For i = 1 To z - 1
        For j = 1 To UBound(otarr, 2)
            nArray(i, j) = otarr(i, j)
        Next j
    Next i
    
    vStack = nArray

End Function

【讨论】:

  • 我注意到您的第二个解决方案返回#VALUE!,例如=vStack({1},{4;5;6})
  • 那是因为第一个被视为一维数组。我并没有为此编程。
【解决方案2】:

已更新动态可用范围

这个函数应该创建你想要的。请注意,这不考虑空格或标题。 See sample spreadsheet with working result.

Function combineRange(ParamArray theRanges() As Variant) As Variant()
    Dim totalColumns As Long, z As Long, r As Long, g As Long, aCell As Range
    
    ReDim zRanges(0) As Range
    For r = LBound(theRanges) To UBound(theRanges)
        ReDim Preserve zRanges(r)
        Set zRanges(r) = theRanges(r)
        Set zRanges(r) = Intersect(zRanges(r), zRanges(r).Worksheet.UsedRange)
       
        totalColumns = Application.WorksheetFunction.Max(zRanges(r).Columns.Count, totalColumns)
    Next r
    
    r = 1
    
    ReDim theRay(1 To totalColumns, 1 To r)
    
    For z = LBound(zRanges) To UBound(zRanges)
        For Each aCell In zRanges(z).Columns(1).Cells
           ReDim Preserve theRay(1 To totalColumns, 1 To r)
            For g = 1 To zRanges(z).Columns.Count
                theRay(g, r) = aCell.Offset(0, g - 1).Value
            Next g
            r = r + 1
        Next aCell
    Next z
    
    combineRange = Application.WorksheetFunction.Transpose(theRay)
End Function

【讨论】:

  • 谢谢!!这是我正在寻找的基本思想,但是有没有办法让它接受两个以上的范围?我在问题中使用了两个作为示例,但 Google 表格语法的优点在于它允许您放置任意数量的范围。我为混乱道歉,我应该在这个问题上更清楚。再次感谢!
  • 是的,您可以使用ParamArray 创建无限数组。查找有关用户定义函数的内容,我怀疑您会弄清楚的。如果没有,请发布另一个问题。你介意点击accept,因为这确实解决了你的问题吗?谢谢,很高兴它有效。
  • @PGSystemTester 我认为这个问题比具体的例子更广泛。 OP只是以过滤器公式为例,而不是最终情况。问题是如何使用{range1;range2} 并获得一个可以在其他公式中使用的单个数组,例如表格中的一个。
  • 好的。我将其更新为动态的。 @devlife 你现在有一个无限范围的动态结果......
猜你喜欢
  • 2014-01-08
  • 2014-10-04
  • 1970-01-01
  • 2011-06-06
  • 1970-01-01
  • 1970-01-01
  • 2011-04-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多