Arrays 在数组VBA中进行大范围解析的最有效方法

Arrays 在数组VBA中进行大范围解析的最有效方法,arrays,vba,excel,matrix,Arrays,Vba,Excel,Matrix,我在excel中有大量数据,我想将这些数据解析为用户定义函数的数组。范围为2250 x 2250。通过for循环解析每个单元格的时间太长,并且太大,无法通过此方法分配给数组: dim myArr as Variant myArr = range("myrange") 在这里进行头脑风暴,在每一列中进行解析并加入数组会更有效吗?有什么想法吗 谢谢你就快到了 您需要的代码是: Dim myArr as Variant myArr = range("myrange").Value2 请注意,我使用

我在excel中有大量数据,我想将这些数据解析为用户定义函数的数组。范围为2250 x 2250。通过for循环解析每个单元格的时间太长,并且太大,无法通过此方法分配给数组:

dim myArr as Variant
myArr = range("myrange")
在这里进行头脑风暴,在每一列中进行解析并加入数组会更有效吗?有什么想法吗

谢谢

你就快到了

您需要的代码是:

Dim myArr as Variant
myArr = range("myrange").Value2
请注意,我使用的是范围的.Value2属性,而不仅仅是读取格式和区域设置的“Value”,它可能会损坏任何日期

另外,请注意,我没有费心重新定义并指定数组的维度:Value和Value2属性是一个二维数组,1到Rowcount,1到Col Count。。。除非它是单个单元格,否则它将是一个标量变量,它会破坏任何需要数组的下游代码。但这不是已知2250 x 2250范围的问题

如果反转操作并将数组写回某个范围,则需要将接收范围的大小精确设置为数组的尺寸。同样,你问的问题不是你的问题:但这两个操作通常是同时进行的

一般原则是,工作表的每次“命中”大约需要二十分之一秒——有些机器速度快得多,但它们都有糟糕的日子——而“命中”或将单个单元格读取到变量中几乎与将700万单元格范围读取到变量数组中完全相同。两者都比一次在一个单元格中读取该范围快几百万倍

无论哪种方式,只要完成“读入”并停止与工作表交互,就可以将VBA中的任何操作计算为零时间

这些数字都非常粗略,但一般原则仍然适用,直到您开始分配不适合工作内存的数组时为止,这也不是您今天的问题

记住在完成后删除数组变量,而不是依赖它超出范围:对于这样大小的范围,这将产生不同。

您就快到了

您需要的代码是:

Dim myArr as Variant
myArr = range("myrange").Value2
请注意,我使用的是范围的.Value2属性,而不仅仅是读取格式和区域设置的“Value”,它可能会损坏任何日期

另外,请注意,我没有费心重新定义并指定数组的维度:Value和Value2属性是一个二维数组,1到Rowcount,1到Col Count。。。除非它是单个单元格,否则它将是一个标量变量,它会破坏任何需要数组的下游代码。但这不是已知2250 x 2250范围的问题

如果反转操作并将数组写回某个范围,则需要将接收范围的大小精确设置为数组的尺寸。同样,你问的问题不是你的问题:但这两个操作通常是同时进行的

一般原则是,工作表的每次“命中”大约需要二十分之一秒——有些机器速度快得多,但它们都有糟糕的日子——而“命中”或将单个单元格读取到变量中几乎与将700万单元格范围读取到变量数组中完全相同。两者都比一次在一个单元格中读取该范围快几百万倍

无论哪种方式,只要完成“读入”并停止与工作表交互,就可以将VBA中的任何操作计算为零时间

这些数字都非常粗略,但一般原则仍然适用,直到您开始分配不适合工作内存的数组时为止,这也不是您今天的问题

记住在完成后删除数组变量,而不是依赖它超出范围:对于这样大小的范围,这会产生不同。

这很好

Sub T()
    Dim A() As Variant

    A = Range("A2").Resize(2250, 2250).Value2

    Dim i As Long, j As Long
    For i = 1 To 2250
        For j = 1 To 2250
            If i = j Then A(i, j) = 1
        Next j
    Next i

    Range("A2").Resize(2250, 2250).Value2 = A
End Sub
这个很好用

Sub T()
    Dim A() As Variant

    A = Range("A2").Resize(2250, 2250).Value2

    Dim i As Long, j As Long
    For i = 1 To 2250
        For j = 1 To 2250
            If i = j Then A(i, j) = 1
        Next j
    Next i

    Range("A2").Resize(2250, 2250).Value2 = A
End Sub

我认为最好的选择是:

尽量将数据限制在一个合理的数字,比如一次1000000个值。 添加一些错误处理以捕获内存不足错误,然后重试,但将大小减半,然后再减三分之一、四分之一等,直到它正常工作。
无论哪种方式,如果我们使用的数据集的大小顺序为5000000个值,并且您希望确保程序能够运行,那么您需要调整代码以分割数据。

我认为最好的选择是:

尽量将数据限制在一个合理的数字,比如一次1000000个值。 添加一些错误处理以捕获内存不足错误,然后重试,但将大小减半,然后再减三分之一、四分之一等,直到它正常工作。
无论哪种方式,如果我们使用的数据集的顺序为5000000个值,并且您希望确保程序能够运行,那么您需要调整代码以分割数据。

我刚刚设置了一个数据范围为a1的工作簿
将2250X2250的范围读取到chn2250,并使用x=rangea1:chn2250.Value2将其读入名为x的变量数组,然后仅为确保其工作,执行了debug.print x2,2。整个行动不到一秒钟。因此,我建议使用一个变体数组。尝试将@Kyle建议的.Value或.Value2添加到上面的数组中。我没有明确说明.Value2,但这确实是一个性能增强程序。2250×2250×8字节/double=38.6 Mb,这应该不会对内存造成任何压力。@ja72您如何知道它们是double?如果它们都是1024长度的字符串呢?这是一个变量数组…带有数字的变量需要16字节的内存。带有字符的变量数据类型通常需要22字节的内存加上字符串所需的内存。这甚至不涉及数组结构本身所使用的内存。我只是设置了一个工作簿,其中数据的范围为a1到chn2250,范围为2250X2250,并使用x=rangea1:chn2250.Value2将其读入一个名为x的变量数组,然后确保它能正常工作,并执行了debug.print x2,2。整个行动不到一秒钟。因此,我建议使用一个变体数组。尝试将@Kyle建议的.Value或.Value2添加到上面的数组中。我没有明确说明.Value2,但这确实是一个性能增强程序。2250×2250×8字节/double=38.6 Mb,这应该不会对内存造成任何压力。@ja72您如何知道它们是double?如果它们都是1024长度的字符串呢?这是一个变量数组…带有数字的变量需要16字节的内存。带有字符的变量数据类型通常需要22字节的内存加上字符串所需的内存。这里甚至没有讨论数组结构本身所使用的内存。嗨,尼罗,非常感谢你的详细解释。我没有想到使用Value2,而且它似乎应该可以工作。但是,我可能会耗尽内存容量。宏现在中断,表示内存不足。由于矩阵中的每个单元格都有一个函数,因此该表的大小为70k kb。你还有其他的建议吗?如果没有,我可以尝试删除一些冗余信息。@Daniel-宏是否在arr=Range.Value2语句中中断?您所能做的是有限的,但是声明一个范围对象变量并使用它可能会有所帮助;与设置应用程序一样。计算=xlCalculationManual@Daniel-如果这些步骤无法解决问题,则下一步是手动重新分配阵列,然后将范围值传递给阵列:重新分配arr1到rng.Rows.Count,1到rng.Columns.Count,然后尝试arr=rng.Value2…之后的步骤是以块的形式加载范围-一次加载1000行或1000列。另外:您正在使用Option.Explicit或VBA中的'Require Variable Declaration'选项?@NigelHeffernan在添加.Value2时,似乎代码速度提高了约10%…它对使用.Formula解决OP.FYI问题没有任何作用,因为我的数据集花费了大约2倍的时间,这很有意义,因为字符串更大。@Profex-Value2是或应该是读取某个范围内的值时的第一件事;其他一切都会使您对本地格式产生依赖。规范示例使用.Value2检索基础日期序列。您好,非常感谢您的详细解释。我没有想到使用Value2,而且它似乎应该可以工作。但是,我可能会耗尽内存容量。宏现在中断,表示内存不足。由于矩阵中的每个单元格都有一个函数,因此该表的大小为70k kb。你还有其他的建议吗?如果没有,我可以尝试删除一些冗余信息。@Daniel-宏是否在arr=Range.Value2语句中中断?您所能做的是有限的,但是声明一个范围对象变量并使用它可能会有所帮助;与设置应用程序一样。计算=xlCalculationManual@Daniel-如果这些步骤无法解决问题,则下一步是手动重新分配阵列,然后将范围值传递给阵列:重新分配arr1到rng.Rows.Count,1到rng.Columns.Count,然后尝试arr=rng.Value2…之后的步骤是以块的形式加载范围-一次加载1000行或1000列。另外:您正在使用Option.Explicit或VBA中的'Require Variable Declaration'选项?@NigelHeffernan在添加.Value2时,似乎代码速度提高了约10%…它对使用.Formula解决OP.FYI问题没有任何作用,因为我的数据集花费了大约2倍的时间,这很有意义,因为字符串更大。@Profex-Value2是或应该是读取某个范围内的值时的第一件事;其他一切都会使您对本地格式产生依赖。规范的示例是使用.Value2检索基础日期序列。谢谢,这是一个有趣的技巧。。。是否可以检查是否声明范围变量,将其设置为mo
nster范围,并且从这个范围变量填充数组也可以吗?此错误可能与计算机有关,但最直接的原因是VBA在尝试解释Range[我们将在运行时解析的某些字符串]时,对需要分配的内存进行了胡乱猜测。Value2,而不是具有VTable的行为良好的对象,或者,正如您向我们展示的那样,一个范围返回函数具有明确定义的大小。例如,设置r=range…Resize。。然后VAL=r.Values2?这和上面一样-不完全一样。就代码的意图而言,这两种方法是相同的。但是,编译器和运行时行为是否足够聪明,能够识别范围对象r在编译时具有已知维度?或者,在使用任意地址字符串将内存分配给从范围方法中读取范围变量的机制时,读取范围变量维度的实现是否不太可能进行胡乱猜测和高估?我猜,arr=RangeA1.Value中的数组是在解析地址字符串之前分配的-可能是整个工作表的尺寸!-然后在行和列计数已知时重新确定尺寸。但是声明的范围对象没有.Value属性可以传递给数组变量,直到知道维度,并且运行时引擎必须按照正确的顺序执行任务。当然,完全可能错误消息不是真的“内存不足”:可能是Oops!我现在需要分配内存,但其中一个数字丢失了。我很确定编译器知道范围的大小……这并没有什么区别,因为它是明确地为我们人类指定的。在到达那一行之前,它不会猜测大小或试图分配任何内存…这就是VBA的工作方式。谢谢,这是一个有趣的技巧。。。您是否可以检查声明一个范围变量、将其设置为怪物范围以及从该范围变量填充数组是否也有效?此错误可能与计算机有关,但最直接的原因是VBA在尝试解释Range[我们将在运行时解析的某些字符串]时,对需要分配的内存进行了胡乱猜测。Value2,而不是具有VTable的行为良好的对象,或者,正如您向我们展示的那样,一个范围返回函数具有明确定义的大小。例如,设置r=range…Resize。。然后VAL=r.Values2?这和上面一样-不完全一样。就代码的意图而言,这两种方法是相同的。但是,编译器和运行时行为是否足够聪明,能够识别范围对象r在编译时具有已知维度?或者,在使用任意地址字符串将内存分配给从范围方法中读取范围变量的机制时,读取范围变量维度的实现是否不太可能进行胡乱猜测和高估?我猜,arr=RangeA1.Value中的数组是在解析地址字符串之前分配的-可能是整个工作表的尺寸!-然后在行和列计数已知时重新确定尺寸。但是声明的范围对象没有.Value属性可以传递给数组变量,直到知道维度,并且运行时引擎必须按照正确的顺序执行任务。当然,完全可能错误消息不是真的“内存不足”:可能是Oops!我现在需要分配内存,但其中一个数字丢失了。我很确定编译器知道范围的大小……这并没有什么区别,因为它是明确地为我们人类指定的。在到达那一行之前,它不会猜测内存的大小或试图分配内存……VBA就是这样工作的。