【发布时间】:2016-10-08 00:56:44
【问题描述】:
我在 Excel 中使用 VBA 来使用 XML 文件并将特定信息转储到各个选项卡中。我希望能够组合二维数组。数组具有“已知”数量的列,但具有“未知”数量的行。考虑以下两个数组:
数组1:
a b c
d e f
数组2:
1 2 3
4 5 6
如果我想要以下结果,如何将这些组合到数组中:
数组3:
a b c
d e f
1 2 3
4 5 6
出于好奇,如果我想添加到右侧而不是底部,我将如何编码,如下所示:
数组4:
a b c 1 2 3
d e f 4 5 6
我似乎无法在任何地方找到答案。
请记住,我上面的示例很小,但实际上,我正在尝试一次处理大约 100,000 行数据。如果重要的话,只有六列数据。
这里的目标是组装一个大数组,然后一步将其写入 Excel 工作表,因为当我分段执行时,性能真的很差。
如果可能,我更喜欢不需要迭代的解决方案。
我问这两种方式的原因是实际上我想按顺序添加。例如,假设我有四个数组,A、B、C、D。
首先,添加数组A:
A
然后,添加数组B:
A B
然后,添加数组C:
A B
C
然后,添加数组 D:
A B
C D
等等……
请记住,上述每个数组的大小都会正确“适合”,这意味着 A 和 B 的行数相同,但列数不同。另一方面,A 和 C 的列数相同,但行数不同。等等……
我想使用下面的 Macro Man 代码添加一个演示。这是他提供的(我添加了一点,以便读者可以复制/粘贴):
Option Explicit
Sub Testing()
Dim Array1(0 To 1, 0 To 2) As String
Array1(0, 0) = "a"
Array1(0, 1) = "b"
Array1(0, 2) = "c"
Array1(1, 0) = "d"
Array1(1, 1) = "e"
Array1(1, 2) = "f"
Dim Array2(0 To 1, 0 To 2) As String
Array2(0, 0) = "1"
Array2(0, 1) = "2"
Array2(0, 2) = "3"
Array2(1, 0) = "4"
Array2(1, 1) = "5"
Array2(1, 2) = "6"
Dim i As Long
For i = 1 To 25000
With Range("A" & Rows.Count).End(xlUp).Offset(IIf(IsEmpty([A1]), 0, 1), 0)
.Resize(UBound(Array1, 1) - LBound(Array1, 1) + 1, _
UBound(Array1, 2) - LBound(Array1, 2) + 1).Value = Array1
End With
With Range("A" & Rows.Count).End(xlUp).Offset(IIf(IsEmpty([A1]), 0, 1), 0)
.Resize(UBound(Array2, 1) - LBound(Array2, 1) + 1, _
UBound(Array2, 2) - LBound(Array2, 2) + 1).Value = Array2
End With
Next i
End Sub
当您运行上述代码时,每次都会返回电子表格写入少量数据,这需要很长时间才能运行。在我的双 Xeon 机器上,大概 25-30 秒。
但是,如果您首先重写并填充数组,然后写入电子表格一次,它会在大约一秒钟内运行。
Option Explicit
Sub Testing()
Dim Array1(0 To 99999, 0 To 2) As String
Array1(0, 0) = "a"
Array1(0, 1) = "b"
Array1(0, 2) = "c"
Array1(1, 0) = "d"
Array1(1, 1) = "e"
Array1(1, 2) = "f"
Dim i As Long
For i = 0 To 99999
Array1(i, 0) = "a"
Array1(i, 1) = "b"
Array1(i, 2) = "c"
Next i
With Range("A" & Rows.Count).End(xlUp).Offset(IIf(IsEmpty([A1]), 0, 1), 0)
.Resize(UBound(Array1, 1) - LBound(Array1, 1) + 1, _
UBound(Array1, 2) - LBound(Array1, 2) + 1).Value = Array1
End With
End Sub
我希望看到一个做同样事情的解决方案,除了能够添加“块”数据而不是单个项目。理想情况下,将数组添加到更大的数组中。如果“父”数组以某种方式动态调整自身大小,那就更好了。
约翰·科尔曼在下面的回答效果很好。
我实际上将一些 Macro Man 与 John 的 test() 子例程结合起来,这会动态地重新调整范围的大小:
Option Explicit
Sub test()
Dim A As Variant, B As Variant
ReDim A(0 To 1, 0 To 1)
ReDim B(0 To 1, 0 To 1)
A(0, 0) = 1
A(0, 1) = 2
A(1, 0) = 3
A(1, 1) = 4
B(0, 0) = 5
B(0, 1) = 6
B(1, 0) = 7
B(1, 1) = 8
Dim Array1 As Variant
Array1 = Combine(A, B)
With Range("A" & Rows.Count).End(xlUp).Offset(IIf(IsEmpty([A1]), 0, 1), 0)
.Resize(UBound(Array1, 1) - LBound(Array1, 1) + 1, _
UBound(Array1, 2) - LBound(Array1, 2) + 1).Value = Array1
End With
End Sub
【问题讨论】:
-
我想我误解了“数组”。您可以将所有这些值存储到一个数组中,然后根据需要在 Excel 中显示它们……您可以遍历三列,然后向下一行,重复。或者你可以翻六列,然后向下走一排。我的观点是(AFAIK)Excel 数组不是以某种物理方式存储的……它只是一个项目列表。如何在 Excel 中显示它们取决于您 100%。这有意义吗?
-
我稍微澄清了我的问题。这与最终写入 excel 工作表的 VBA 有关。如果我点击表格以一次更新每个值甚至是大块值,则需要很长时间。当我从单独存储每个值到将它们以块的形式放置在工作表上时,性能显着提高。我希望找到一种方法来做同样的事情,但在 VBA 中进一步组合数组。
-
Redim PRESERVE命令只能扩展最后一个rank。您可能最好创建一个通过添加 UBounds 变暗的新数组,然后从那里填充。远离.Transpose来完成redim。您的 10 万“行”数据超出了其限制。 -
@BruceWayne 数组,即使在 VBA 中,也可以有多个维度。这是一个二维数组,在视觉上看起来像一组单元格。 See this了解更多信息
-
@BruceWayne 圣牛,蝙蝠侠。 VBA 中的数组绝对存储为称为 SAFEARRAY 的 OLE 构造。阅读:roblocher.com/whitepapers/oletypes.html