填充临时数组以避免在动态多维数组上使用 Preserve

Posted

技术标签:

【中文标题】填充临时数组以避免在动态多维数组上使用 Preserve【英文标题】:Populating a temporary array to avoid using Preserve on a dynamic, multidimensional array 【发布时间】:2015-11-17 15:52:42 【问题描述】:

作为 VBA 的初学者,我正在尝试学习这些内容的大部分内容,请原谅我的灰尘。

我正在编写一个子程序,用于读取文本文件中的行。每行由空格分隔,以 ' 作为文本标识符。我要求将每一行拆分为多维数组的字段。

Sub ReadLines()
Dim LineValues() As String
Dim row As Long, col As Long
Dim DataArray() As String
Dim TempArray() As String
Dim FileContent As String
Dim FilePath As String

FilePath = "c:\mytextfile.txt"
row = 0
TextFile = FreeFile
Open FilePath For Input As TextFile
FileContent = Input(LOF(TextFile), TextFile)
Close TextFile
LineValues = Split(FileContent, vbCrLf)

For X = LBound(LineValues) To UBound(LineValues) 
 If Len(Trim(LineValues(X))) <> 0 Then
 DataArray = Split(LineValues(X), "'") 
 col = UBound(DataArray)
 TempArray = DataArray
 ReDim DataArray(col, row) 
 For i = LBound(TempArray) To UBound(TempArray)
 DataArray(i, row) = TempArray(i)
 Next i
 End If
 row = row + 1 
Next X

在与 ReDim Preserve 的多维问题作斗争后,我得到了这段代码。 (只能修改最后一个维度)我的文本文件中的多维数组将有未知的列和行,具体取决于用户输入。

这段代码正确地完成了这个过程……但就是不能正确地存储数组元素!上面的意图是使用临时数组(TempArray),同时我重新调整(并清空)我感兴趣的数组(DataArray),然后将最初从 DataArray 中的元素复制回调整大小的维度。

但是,当单步执行代码时,我可以看到每一行都被正确放置,但随后在每次迭代中被删除, DataArray = Split(LineValues(X), "'")

因此,我基本上有一个矩阵,其大小由总行数决定,但仅由最后一行的列数(以及最后一行的值)决定。

我知道为什么会发生这种情况,但是这里有人可以提出解决方案吗?作为一个初学者,这有点令人抓狂!

编辑,完整的问题描述

为了完全澄清,这是一个子例程,我将作为脚本的一部分调用,该脚本读取包含不相关数据的文本文件。这个文本文件看起来有点像这样,(参考的模糊是故意的)

 '<irrelevant text I want to ignore until seeing pattern 'NumberOfVariables?'>
    ...
    ...
    NumberOfVariables?
    NUMBEROFVARIABLES
    'for the end user, I need to be able to pull information from each of these fields assigned to a variable to create strings as headers as per a specific format
'note that variable and variable type 
    Variable#1 VARIABLETYPE Location? LOCATION UNITS DESCRIPTION 'text for each field is enclosed as follows '' (code formatting on site prevents me doing this)
    Variable#2 VARIABLETYPE Location? LOCATION UNITS DESCRIPTION
    ...
    Variable#NUMBEROFVARIABLES
    ' from here there is a column of data that is assigned to each variable such that
    Variable#1Element1         Variable#2Element1       'etc until #NUMBEROFVARIABLES
    Variable#1Element2         Variable#2Element2 
    Variable#1Element3         Variable#2Element3 
    Variable#1FinalElement     Variable#2FinalElement 

主要目标是使用原始帖子中的脚本在多维矩阵中获取这些字段,然后我可以针对一些条件语句使用这些字段来根据最终用户的需求获取标题字符串。

然后我会从这里找到一种方法让数据列与每个变量匹配,以便可以将其自动导入 Excel。

更进一步的是某种带有下拉菜单的 MsgBox,它可以选择要复制的变量,但在我目前的开发阶段,这是天上掉馅饼!

【问题讨论】:

你打算如何处理最终数据?您可以简单地使用数组数组。 您正在重新排列 Dataarray 每一行。每次都会删除所有数据。这需要移到循环之外,但这需要您知道列的最大范围。你可以猜得很高。仅供参考,Excel 中有本地工具可以做到这一点。 这就是我不喜欢数组的原因。如果我是你,我会将每行的 DataArray 存储在字典中并继续直到完成。使用字典不需要调整大小,而且由于调整数组大小以适应所有数据,因此您永远不会有一个包含空值的数组。 在我看来你可以从 UBound(LineValues) 中找到行数?然后你可以简单地为列 redim preserve。 @BruceWayne 这种方法在原始脚本中解决了 ReDim Preserve 只能更改最后一个维度的问题。 (因此导致我早早秃顶) 【参考方案1】:

试试这个。我没有测试过:

Sub ReadLines()

    Const FilePath$ = "c:\mytextfile.txt"

    Dim iFile%, c&, i&, j&, k&, Content$, Lines, Temp, Data

    c = 499
    Open FilePath For Input As #iFile
    Content = StrConv(InputB(LOF(iFile), iFile), vbUnicode)
    Close #iFile

    Lines = Split(Content, vbCrLf)
    ReDim Data(0 To UBound(Lines), 0 To c)

    For i = 0 To UBound(Lines)
        If Len(Trim$(Lines(i))) Then
            Temp = Split(Lines(i), "'")
            If k < UBound(Temp) Then k = UBound(Temp)
            If k > c Then
                c = k * 2
                ReDim Preserve Data(0 To UBound(Lines), 0 To c)
            End If
            For j = 0 To UBound(Temp)
                Data(i, j) = Temp(j)
            Next
        End If
    Next
    ReDim Preserve Data(0 To UBound(Lines), 0 To k)

End Sub

【讨论】:

如果 k > c 那么为什么不直接使用 k 作为数组大小定义器 ReDim Preserve Data(0 To UBound(Lines), 0 To k)?只是好奇这是如何工作的。 @JDonald 你能做到吗? @ExcelHero 抱歉耽搁了(开始写对所有这些惊人和意想不到的输入量的回复),但这几乎可以解决我在原始问题中提出的问题。我在声明 iFile 时遇到了问题,所以我把它从你更整洁的方法中去掉,并按照我在互联网上搜索不到 1 周的经验教会我的方式去做。 Dim iFile As Integer: iFile = FreeFile Dim c&amp;, i&amp;, j&amp;, k&amp;, Content$, Lines, Temp, Data 稍作改动后效果很好。 @ClintStreet 我只是根据我事先阅读的内容进行猜测,但是在将 c 重新定义为 2k 之前进行的 k > c 检查是否将阵列中 ReDim Preserve 的变化最小化为性能问题? 你不想经常使用 Redim Preserve 我猜这就是为什么让 c = k * 2 是消除它的好方法。 IMO 使用字典会好得多。不幸的是,这些天我的时间有点紧,所以我无法使用字典提供答案。【参考方案2】:

我要求将每一行拆分为多维数组的字段。

好吧,我不知道这是否真的是真的,因为我不确定您最终 对数据做了什么,但无论如何,一个超级简单的替代方案是将 .txt 文件读入工作簿结构。

为此,请使用带有参数的Workbooks.OpenText 方法:TextQualifier:=xlTextQualifierSingleQuote(根据您的用例,可能需要一些额外的可选参数)。

这应该会在“字段”(工作表中的列)中打开正确分隔的文本文件。

从那里,您可以将工作表的 UsedRange.Value 分配给变量数组。

【讨论】:

作为一个编程初学者(更不用说 VBA),我很可能使用了错误的工具或过度思考了问题。我知道 Excel 中的导入文本分隔函数(我已经录制了一个宏并看到了您所说的 True/False 参数),但是使用 UsedRange.Value 的变体对我来说是一种新方法。下面 Excel Hero 的方法解决了最初的问题,但请参阅上面的评论,我扩展了我试图完成的全部任务,看看我的方法是否效率低下。

以上是关于填充临时数组以避免在动态多维数组上使用 Preserve的主要内容,如果未能解决你的问题,请参考以下文章

动态处理多维数组作为 UIImage 数组

使用多维数组构建对象以动态创建列

如何在多维数组/网格c ++中创建List

如何将零填充的多维数组传递给 C++ 中的函数?

PHP填充多维关联数组 - 最简单的方法

动态多维数组c#