2

我需要将数据从 excel 工作表中提取到一个数组中,该数组将在使用 VBScript 作为脚本语言(快速测试专业版)的应用程序中使用。我们可以使用以下代码:

' ws must be an object of type Worksheet
Public Function GetArrayFromWorksheet(byref ws)
    GetArrayFromWorksheet = ws.UsedRange.Value
End Function

myArray = GetArrayFromWorksheet(myWorksheet)
MsgBox "The value of cell C2 = " & myArray(2, 3)

一切都很好,但不幸的是,返回的数组不仅包含文字文本字符串,还包含日期、整数、双精度等类型的原语。数据被转换多次。

[编辑]示例:当输入=NOW()一个单元格并将单元格格式设置hh:mm为显示值17:45 时,上述方法返回一个类型的变量double和一个类似41194.7400990741的值

以下解决方案效果更好:我可以使用该.Text属性从单元格中获取文字文本,但它们仅适用于一个单元格,而不适用于一系列单元格。我不能像使用.Value属性一样对数组执行此操作,因此我必须一次填充一个单元格:

Public Function GetArrayFromWorksheet_2(byref ws)
    Dim range, myArr(), row, col
    Set range = ws.UsedRange

    ' build a new array with the row / column count as upperbound
    ReDim myArr(range.rows.count, range.columns.count)

    For row = 1 to range.rows.count
        For col = 1 to range.columns.count
            myArr(row, col) = range.cells(row, col).text
        Next
    Next

    GetArrayFromWorksheet_2 = myArr
End Function

但是哎哟......一个嵌套的for loop. 是的,在大型工作表上,性能明显下降。
有人知道更好的方法吗?

4

3 回答 3

2

正如我们在评论中介绍的那样,为了避免这个问题,您需要在某个时候循环遍历数组。但是,我发布此内容是因为它可能会显着提高速度,具体取决于工作表上的数据类型。200 个单元格中有一半是数字的,这大约快了 38%。使用相同比例的 600 个细胞,改善率为 41%。

通过遍历数组本身,并且只检索.Text解释为双精度(数字)的 for 值,如果有大量非双精度数据,您可以看到速度提高。这不会检查.Text带有文本的单元格、格式化为日期的日期或空白单元格。

Public Function GetArrayFromWorksheet_3(ByRef ws)

    Dim range, myArr, row, col
    Set range = ws.UsedRange

    'Copy the values of the range to temporary array
    myArr = range
    'Confirm that an array was returned.
    'Value will not be an array if the used range is only 1 cells
    If IsArray(myArr) Then
        For row = 1 To range.Rows.Count
            For col = 1 To range.Columns.Count
                'Make sure array value is not empty and is numeric
                If Not IsEmpty(myArr(row, col)) And _
                            IsNumeric(myArr(row, col)) Then
                    'Replace numeric value with a string of the text.
                    myArr(row, col) = range.Cells(row, col).Text
                End If
            Next
        Next
    Else
        'Change myArr into an array so you still return an array.
        Dim tempArr(1 To 1, 1 To 1)
        tempArr(1, 1) = myArr
        myArr = tempArr
    End If

    GetArrayFromWorksheet_3 = myArr
End Function
于 2012-10-12T16:15:59.447 回答
0
  • 将工作表复制到新工作表中。
  • 复制粘贴值以删除公式
  • 对每一列的列做一个文本,将每一列变成文本
  • 像最初一样加载阵列
  • 删除新工作表
于 2012-10-12T16:25:08.907 回答
0

如果不遍历工作表,您将无法快速轻松地完成此操作。如果您将上述技术与 2 行代码一起使用,则它必须是一个变体类型数组。

我从我的代码中包含了一个真实的示例,它在 6 行中完成,因为我喜欢 A) 使用工作表对象和 B) 将变量与原始的最后一行放在手边。

Dim wsKeyword As Worksheet
Set wsKeyword = Sheets("Keywords")

Dim iLastKeywordRow As Long
iLastKeywordRow = wsKeyword.Range("A" & wsKeyword.Rows.Count).End(xlUp).Row

Dim strKeywordsArray As Variant
strKeywordsArray = wsKeyword.Range("A1:N" & iLastKeywordRow).Value

请注意,您的数组必须是这样使用的变体。

Variants 像这样工作的原因是,当您创建一个变体数组时,数组中的每个“单元格”都设置为一个变体类型。然后每个单元格将其变体类型设置为分配给它的任何类型的值。因此,分配字符串的变体被设置为 variant.string,现在只能用作字符串。在您的原始示例中,您的时间值似乎存储为 variant.time 而不是 variant.string。

有两种方法可以解决您的原始问题 1) 循环并以更多控制执行该过程,例如双嵌套 for 循环。在另一个答案中解释,它可以让您完全控制 2)将所有数据按原样存储在数组中,然后将其重新格式化为第二个数组,或者在使用时将其格式化为所需的文本(两者都应该更快)

于 2012-10-12T20:53:14.167 回答