如何获取复杂数组的重新计算副本

2024-04-21

我需要计算一个未知的复杂数组并获得它的完美重新计算副本,但我不知道该数组的外观。为了 例子:

MyArray = array(15, 22, array(1, array(7, 3), 9))
or
MyArray = Range("A1:B17")
or
a filled up MyArray(9, 20, 8, 3) which may contain other unknown arrays

为了获取这些值,我通常会循环使用For Each ...每次在数组中找到数组时都会调用自己。但是我无法将这些值放回其中。让我们尝试一个简单的例子:

Sub Test()
  Dim a As Variant, b As Variant
  a = Array(1, 2)
  For Each b In a
    b = b + 1
  Next
  For Each b In a
    Debug.Print b
  Next
End Sub

虽然这很容易更好地解决它,但它仍然显示了我的问题。仅拥有一个副本并不能让我将新值放回其中。假设只有一维数组和值:

Function Test2(a As Variant) As Variant
  Dim i As Long
  If IsArray(a) Then
    For i = LBound(a) To UBound(a)
      a(i) = Test2(a(i))
    Next
    Test2 = a
  Else
    Test2 = a + 1
  End If
End Function

Sub Test3()
  Dim a As Variant
  a = Array(1, Array(2, 3))
  Debug.Print "Array(" & a(0) & ", Array(" & a(1)(0) & "," & a(1)(1) & "))"
  a = Test2(a)
  Debug.Print "Array(" & a(0) & ", Array(" & a(1)(0) & "," & a(1)(1) & "))"
End Sub

虽然这适用于一维数组,但不适用于 n 维数组。我仍然不知道我的数组会是什么样子。

是否有针对未知数组的解决方法或将值放回数组内的方法For Each ...-loop?

转换MyArray(1, 1) to Array(Array(,),Array(,))一开始看起来不错,但由于事实上将其转换回来有点不可能Array(Array(,),Array(,))仍然是一个有效的数组。此外,由于可能的复杂性,“记住”如何再次将其组合在一起几乎是不可能的。至少不会有任何集合或自我声明的类型。

Edit:
关于实际答案,可能并不完全清楚我想要什么。

Dim MyArray(5, 5) as Variant
MyArray(0, 0) = 7
MyArray(0, 1) = 9
...
MyArray(4, 0) = 7
...

这是一个简单的二维数组,我的Test2无法处理它MyArray(i)。这会导致错误。所以每个答案都像我的函数一样是不正确的。


考虑一下:

Sub Test()
    Dim a
    a = Array(1, Array(2, Array(4, 5, 6)))
    Process a
    PrintIt a
End Sub
Sub Process(a)
    For i = 0 To UBound(a)
        If Not IsArray(a(i)) Then
            a(i) = a(i) + 1
        Else
            Process a(i)
        End If
    Next
End Sub
Sub PrintIt(a)
    For i = 0 To UBound(a)
        If Not IsArray(a(i)) Then
            Debug.Print a(i)
        Else
            PrintIt a(i)
        End If
    Next
End Sub

.

UPDATE

所以我看到你为此付出了努力,所以我会做出更多贡献。我的目标是帮助您和任何阅读本文的人学习。

正如我在第一条评论中提到的......Testing for rank of an array requires error handling or SAFEARRAY descriptor interrogation.

所以我给你两种方法。您找到了一种方法来实现前者,但为了以我上面的答案为基础,以下是我仅使用 VBA 来实现的方法:

Sub Test()
    Dim a, b
    b = [{11,12;13,14}]
    a = Array(1, Array(2, Array(4, 5, b)))
    Iterate a
    Iterate a, 1
End Sub
Sub Process(a)
    a = a + 1
End Sub
Sub Iterate(a, Optional bReport As Boolean = False)
    Dim rank&, i&, j&, z
    If IsArray(a) Then
        Select Case ArrayRank(a)
            Case 1
                For i = LBound(a) To UBound(a)
                    Iterate a(i), bReport
                Next
            Case 2
                For i = LBound(a) To UBound(a)
                    For j = LBound(a, 2) To UBound(a, 2)
                        Iterate a(i, j), bReport
                    Next
                Next
        End Select
    Else
        If bReport Then
            Debug.Print a
        Else
            Process a
        End If
    End If
End Sub
Function ArrayRank&(a)
    Dim j&, k&
    On Error Resume Next
    For j = 1 To 60
        k = LBound(a, j)
        If Err Then ArrayRank = j - 1: Exit For
    Next
End Function

是的,仅使用 VBA,由于 VBA 数组元素\等级索引的实现方式,您必然需要使用硬编码开关,例如 Select Case。我上面更新的答案展示了如何使用前两个维度。当然,更高的等级需要额外的箱子。

然而(就像我前面所说的那样)另一种方法是询问 SAFEARRAY 描述符。这提供了一个通用的解决方案,但需要对 COM 变量的内部结构有更深入的了解。我已经展示了它适用于等级 1、2 和 3。但它应该适用于所有等级:

Private Declare Sub GetMem2 Lib "msvbvm60" (ByVal Addr As Long, RetVal As Integer)
Private Declare Sub GetMem4 Lib "msvbvm60" (ByVal Addr As Long, RetVal As Long)

Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)


Sub Test()
    Dim a, b, c
    b = [{110,120;130,140}]
    ReDim c(1 To 1, 1 To 1, 1 To 3)
    c(1, 1, 1) = 500
    c(1, 1, 2) = 600
    c(1, 1, 3) = 700
    a = Array(1, Array(2, Array(40, 50, b, c)))
    Iterate a
    Debug.Print
    Iterate a, 1
End Sub
Sub Process(a)
    a = a + 1
End Sub
Sub Iterate(a, Optional bReport As Boolean = False)
    Dim t%, dims%, elems&, bounds&(), ptr&, ptrBase&, ptrData&
    Dim rank&, c&, i&, z
    If IsArray(a) Then
        ptr = VarPtr(a)
        GetMem2 ptr, t
        If (t And 16384) = 16384 Then   'ByRef Variant Array (16384 = VT_BYREF)
            GetMem4 ptr + 8, ptr
            GetMem4 ptr, ptrBase
        Else
            GetMem4 ptr + 8, ptrBase
        End If
        GetMem4 ptrBase + 12, ptrData
        GetMem2 ptrBase, dims
        c = UBound(a) - LBound(a) + 1
        For i = 2 To dims
            c = c * (UBound(a, i) - LBound(a, i) + 1)
        Next
        For i = 0 To c - 1
            CopyMemory ByVal VarPtr(z), ByVal ptrData + i * 16, 16&
            Iterate z, bReport
            CopyMemory ByVal ptrData + i * 16, ByVal VarPtr(z), 16&
            CopyMemory ByVal VarPtr(z), 0&, 16&
        Next
    Else
        If bReport Then
            Debug.Print a
        Else
            Process a
        End If
    End If
End Sub

注意:API 是针对 32 位 Excel 声明的。如果您也希望支持 64 位,则需要对其进行编辑。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何获取复杂数组的重新计算副本 的相关文章

  • Excel 2007 Visual Basic 编辑器:占用空格,四处移动光标

    我无法解决这个问题 我发现了类似的问题here https stackoverflow com questions 1164138 vba editor auto deletes spaces at the ends of lines bu
  • Excel Power Query:如何将巨大的表格逆透视并转置为可读格式以进行分析

    I have this table that looks similar to this 我想将其改造为如下所示 这个想法是对表进行逆透视 或转置 以便可以将其输入到其他 BI 工具中 并且可以读取以进行分析 我有大约 20 个这样的表 有
  • C# 导出为 Excel 格式

    行动结果 var strLawTable new StringBuilder strLawTable Append thead strLawTable Append tr strLawTable Append th Dollar th st
  • 如何使用 VBA 在 PowerPoint 中取消形状组合后按类型重新组合形状

    继我的出色回答之后上一个问题 https stackoverflow com questions 74339247 how to rename shapes within grouped groups in powerpoint with
  • VBA - 从 Internet Explorer 的框架通知栏中选择另存为

    我正在尝试通过以下方式下载另存为的文件框架通知栏的互联网浏览器 然而 经过大量搜索后 我只找到了点击解决方案save在框架通知栏上 到目前为止 我一直在尝试另存为示例站点上的文件 http www tvsubtitles net subti
  • 在 VBA 中接收文件创建通知,无需轮询

    我正在编写一个与 ScanSnap 扫描仪集成的程序 ScanSnap 扫描仪不支持 TWAIN 扫描文档后 它会自动保存为 PDF 我想监视保存文件的目录 并在文件出现 并完成写入 时采取一些操作 一种简单的方法是使用 MS Access
  • 如何将新行插入范围并复制公式

    我有一个命名范围 如下所示 覆盖 A2 D3 ITEM PRICE QTY SUBTOTAL 1 10 3 30 1 5 2 10 TOTAL 40 我要使用 VBA 将新行插入到复制公式而不是值的范围中 任何提示 链接都非常感谢 这应该可
  • 如何在 Excel 的 VBA 中求负数的立方根?

    我正在尝试在 Excel 的 VBA 中计算负数的立方根 在 Excel 工作表中取负数的立方根效果很好 2 1 3 1 25992 然而 相同的概念被编码到 VBA 中 2 1 3 gives a VALUE 将值返回到工作表时出错 我怀
  • 结合使用 COUNTIF 和 VLOOKUP EXCEL

    我有多个电子表格workbook我想要以下基本内容English talk IF worksheet1 cell A3 出现在 工作表 2 B 列中 计算它在 工作表 2 b 列中出现的次数 换句话说 让我们说A3 BOB smith 在工
  • 使用工作表作为数据源的 VSTO Excel 的简单示例

    我想我遇到了 最简单的答案是最难找到的答案 的情况 而且我还没有遇到过任何搜索能够以直接的方式给我这个答案 这是为了Excel 2010 and VS 2010在现有 VSTO C 项目中 我有一个 Excel 工作表 其中包含 4 列数据
  • 如何使用 VBA 将符号/图标格式化为单元格而不使用条件格式

    我使用 VBA 代码放置条件格式以覆盖大型表格中的值 每个单元格使用 2 个公式来确定使用 3 个符号中的哪一个 我需要根据列使用不同的单元格检查每个单元格的值 因此据我了解 我必须将条件格式规则单独放置在每个单元格上 以确保每个单元格中的
  • 使用按钮从 Django 项目根下载文件

    So this is the webpage I m creating atm with Django 1 8 希望用户能够将数据导出为 csv 当用户 在框中写下 Reddit 子版块名称 按下 获取数据 按钮 会发生什么 它创建了一个
  • 无法加载文件或程序集“Microsoft.Office.Interop.Excel”

    我在 WinForm 应用程序中使用 Excel 时遇到问题 当我在多台计算机上尝试它时 它在它们上运行得很好 但是当我在另一台计算机上尝试它时 它会给我 System IO FileLoadException 无法加载文件或程序集 错误
  • Excel UserForm 动态 TextBox 控件退出事件

    UPDATE 经过对对象浏览器的进一步研究 看来MSForms TextBox既没有实现 Name财产或 Exit事件 仅 Change事件 有没有办法确定具体是哪个TextBox生成更改事件 或者可以使用MSForms Control用这
  • VBA写入Word,更改字体格式

    我正在 Excel 中编写 VBA 脚本 以将基于某些表格的文本输出到 Word 文档 在大多数情况下 一切都很顺利 我在 stackoverflow 的帮助下自学 我有一个相当长的代码 因此将其全部复制到这里会很困难 我将尝试展示相关部分
  • Excel函数:引用单元格中的数组

    我在单元格 A1 中有一个数组 通过 A1 G6 J6 aa b ccc 1 现在我想将单元格 A1 用于 B1 中的数组公式 基本上B1应该是 B1 SUMPRODUKT C6 C12 B6 B12 G6 J6 但我不想直接引用 G6 J
  • VBA:新集合 -> 模块不是有效类型

    我尝试使用集合作为函数的一部分 但是在编译时不断收到错误 模块不是有效类型 即使该函数只是定义一个集合 我也会得到相同的结果 Function CountUniqueTags Dim table As Collection Set tabl
  • VBA添加图表标题

    我只想使用 vba 将图表标题添加到我的图表中 我实际上想对每张纸中的每个图表递归地执行此操作 但我什至无法让 1 个图表工作 这是我的代码 Dim chnam chnam Left ActiveSheet Name Len ActiveS
  • 从命令行使用 VBScript 从 Excel 外部运行 Excel 宏

    我正在尝试从 Excel 文件外部运行 Excel 宏 我目前正在使用从命令行运行的 vbs 文件 但它一直告诉我找不到宏 这是我尝试使用的脚本 Set objExcel CreateObject Excel Application Set
  • 通过 Whatsapp 从 Excel 发送图片

    我们如何通过 Whatsapp 从 Excel 发送图片 我找到了通过以下方式发送消息的vba代码https web whatsapp com https web whatsapp com Sub Test Dim text As Stri

随机推荐