数组vba的最高填充维度

Posted

技术标签:

【中文标题】数组vba的最高填充维度【英文标题】:Highest populated dimension of an array vba 【发布时间】:2010-05-06 13:45:01 【问题描述】:

假设我有一个单维数组(为了简单起见)。有没有一种简单的方法来判断显式分配值的元素的最高索引是多少?除了循环和计数? 我知道 Ubound 找到了数组的最高维度,但这不是我需要的。有没有像 Ubound 这样的东西,但它只计算数组的填充元素,或者填充的最高索引?

我的数组包含字符串。 另外,如果数组是多维的呢?

我正在使用 excel vba。

【问题讨论】:

您的措辞不清楚...“一维数组”的“最高维”是一。你的意思是数组中的最大值吗? 看起来 OP 表示显式分配值的元素的最高 index,而不是具有默认值的元素。在 VBA 中一般没有办法做到这一点,但如果您知道数组可能包含什么样的值,您可能会通过“Application.WorksheetFunction”使用 Excel 的函数之一(例如 COUNTA)来获得所需的值 我同意@jtolle,因此必须根据您需要分享的阵列的更多详细信息来做出具体回答。 抱歉含糊不清/感谢 cmets。我希望我的编辑可以解决问题。 @jtolle 感谢您提供正确的词汇。我尝试了 Application.WorksheetFunction.counta 但它似乎只是告诉我数组中的元素数量如果 arry(1 到 50) 它返回 50,如果 arry(1 到 2, 1 到 3) 它返回 6=2* 3. 【参考方案1】:

简而言之,没有内置机制可以做到这一点,但如果您正在寻找破解它的方法,请继续阅读。

这取决于您如何填充数组。如果它是连续的,最简单的方法是有一个计数器。

如果它是随机的,那么您将面临更大的挑战,即找到最后一个元素的确切索引。一个想法是从最大值开始倒计时。

如果数组已初始化,则可以计算默认值并从 ubound 中减去。

还有其他想法,但您需要更清楚地定义问题,以便我们有更好的回答机会。最好举个例子。

【讨论】:

【参考方案2】:

我建议在填充数组时使用 ReDim Preserve。因此,UBound 将非常适合您。只能对多维数组中的最后一个维度进行 ReDimmed。

【讨论】:

这行得通,但对我正在做的事情来说并不完全实用,这只是意味着我到处都是 ReDim Perserve。这可能没问题。现在我正在做类似的事情,我只是在向数组添加/删除某些内容时跟踪。【参考方案3】:

数组的最高填充元素

您可以在循环中后退一步,直到找到第一个不为空的数组元素。 这相当于“最后一个”填充元素。

简答:

Function HighestPopIdx(ByRef arr) As Long
    For HighestPopIdx = UBound(arr) To LBound(arr) Step -1
        If Not IsEmpty(arr(HighestPopIdx)) Then Exit Function
    Next
End Function

更长的答案:

要获得数组中填充最多的元素,我将使用 For..Next 循环和 IsEmpty 功能。

(为了演示,这个例子有点过于复杂了。)

Sub demo() '(Hit CTRL+G in the VBE to view the output in the Immediate window.)

    'Make a test ARRAY of 5 elements:
    Dim arr(1 To 5)

    Erase arr '(just to make sure the test is starting 'fresh')

    arr(1) = "X"
    arr(2) = 99
    arr(4) = "Y" '3 of the 5 elements have data (highest one is 4)

    Dim elIdx As Long, highestPopEl As Long
    For elIdx = LBound(arr) To UBound(arr)
        If Not IsEmpty(arr(elIdx)) Then highestPopEl = elIdx
    Next elIdx

    Debug.Print "The highest populated element index is " & highestPopEl 'Returns 4

End Sub

...或相反(根据您的情况,第一个示例可能更快。


其他说明:

除了@jtolle 的answer,CountCountA 工作表函数都不起作用:

    With Application.WorksheetFunction
        Debug.Print "Array WS CountA", .CountA(arr) 'returns 5 (Counts cells)
        Debug.Print "Array WS Count", .Count(arr) 'returns 1 (Counts numbers)
    End With

...进一步到 cmets,表明数组和单元格范围的功能相似,但 相同:

    'Make a test RANGE of 5 cells
    Dim rge As Range
    Set rge = Range("A1:A5")

    rge.Clear '(maker sure we're starting fresh)

    Range("A1") = "X"
    Range("A2") = 99
    Range("A4") = "Y" '3 of the 5 cells have data

    With Application.WorksheetFunction        
        Debug.Print "Range WS CountA", .CountA(rge) 'returns 3 (Counts values)
        Debug.Print "Range WS Count", .Count(rge)   'returns 1 (Counts numbers)
    End With

   '... and the VBA [Range.Count] method behaves differently:
    Debug.Print "Range VBA .Count", rge.Count 'returns 5 (Counts cells)

另一方面,如果我的“实际”目标是对数组中的每个元素做一些事情,我会使用 For..Each 循环和 IsEmpty功能。

    'if my actual purpose is to ***do something*** to an ARRAY...
    Debug.Print: Debug.Print "Array [For..Next] :"
    Dim elCnt As Long, el

    For Each el In arr
        If Not IsEmpty(el) Then _
            elCnt = elCnt + 1: Debug.Print "#" & elCnt & ": Element value =", el
    Next el    ' (returns "X", 99, "Y")

    '...and the identical method can be used on a RANGE of cells
    Debug.Print: Debug.Print "Range [For..Next] :"
    Dim clCnt As Long, cl

    For Each cl In rge
        If Not IsEmpty(cl) Then _
            clCnt = clCnt + 1: Debug.Print "#" & clCnt & ": Cell value =", cl
    Next cl    ' (returns "X", 99, "Y")


End Sub

完整输出:

The highest populated element index is 4.

Array WS CountA              5 
Array WS Count               1 
Range WS CountA              3 
Range WS Count               1 
Range VBA .Count             5 

Array [For..Next] :
#1: Element value =         X
#2: Element value =          99 
#3: Element value =         Y

Range [For..Next] :
#1: Cell value =            X
#2: Cell value =             99 
#3: Cell value =            Y

更多信息:

IsEmpty Function UBound Function For...Next Statement

【讨论】:

【参考方案4】:

您可能会考虑使用包含数组变量的自定义类,将项目添加到数组中的代码还会修改另一个变量以跟踪“已使用”索引号。然后你可以包含一个函数来返回存储的“最高索引”数字。

【讨论】:

【参考方案5】:

2018 年的注意事项:这在 Excel 365 中是错误的,在 Excel 2000 中可能是错误的。请参阅 cmets。但我将其作为一个示例,说明在 VBA 中使用 Application.WorksheetFunction() 并不总是与在工作表中使用公式完全相同。


当然,循环确实没有错,但是...

假设你有这个:

Public Sub test()
    Dim a(1 To 3)

    a(1) = 1
    a(2) = "stuff"

    Debug.Print Application.WorksheetFunction.CountA(a)
End Sub

这将打印 '2' [*不,它打印 3 - 请参阅评论***],因为第三个元素的默认值为 '空的'。 (请注意,您的数组必须声明为 Variant 类型才能工作,但它可以包含 String 类型的元素。如果您的数组是 String 类型,则没有任何空!)当然,这假设您知道你所有的空都在最后,因为它只是在计数,而不是实际上返回一个索引。出于同样的原因,您必须知道您的值在二维数组中的分布,这才有意义。

根据您的编辑,我认为这就是您要查找的内容。

【讨论】:

我很惊讶 8 年来没有其他人对此发表评论,但是 这完全是错误的! Copy-并粘贴您的示例返回 3,而不是 2。您是否在发布代码之前未对其进行测试,或者在过去 8 年中基本 Excel-VBA 命令的功能发生了变化? @ashlee,看起来你是对的。我想我会直接从 VBA 编辑器将该代码粘贴到答案中,因为那时我一直在使用它。骄傲让我想去找一台加载了 Excel 2000 的 XP 机器并检查其结果,但我同意即使在过去 18 年(不是 8 年!)中,从 VBA 调用工作表函数也不太可能发生任何变化。我更有可能根据 COUNTA 在工作表中的工作方式做出假设,但这是错误的。这么好抓。谢谢。 嘿没问题,我最近在这里回顾了我的一些早期答案,并被@自己震惊了,我最终删除了一半并编辑了其余的!当我看到你的答案时,我以为我正在学习一个很酷的新技巧并花了一段时间试图让它发挥作用....我想我不妨添加一个答案来展示我最终如何解决我的问题。 旁注 re:您对 Application.WorksheetFunction 的观察在 VBA 中与工作表公式中的行为不同:在 COUNT 的情况下,它实际上 行为相同,但给它范围与数组将不会产生相同的结果,并且值是数字还是文本也会有所不同。另一方面,TRIM 的工作表和 VBA 版本完全不同。 (用字符串中间的连续空格测试它们。)

以上是关于数组vba的最高填充维度的主要内容,如果未能解决你的问题,请参考以下文章

如何从填充零的 3 维 numpy 数组创建 4 维 numpy 数组?

ValueError:无法将大小为0的序列复制到维度为56的数组轴

如何在 SQL Server 中填充我的日期维度表以获得具有此特定值的列?

python如何减小维度

具有两个动态维度和一个静态维度的多维数组

numpy如何沿维度拆分数组?