T.M*_*.M. 4 arrays excel vba matrix
介绍
去年@PrzemyslawRemin 提出了一个问题,即如何在 VBA 中将计数器列添加到现有矩阵中, 而无需额外循环且无需修改工作表。
本示例中的原始矩阵是一个(基于 1 的 2 维)数据字段数组,源自(源单元格仅包含它们的地址字符串;要填充数字的插入行)
Dim matrix As Variant
matrix = Range("A1:C5").value
Run Code Online (Sandbox Code Playgroud)
输入矩阵:------------ ? 想要的结果:
+----+----+----+ +----+----+----+----+
| A1 | B1 | C1 | | 1 | A1 | B1 | C1 |
+----+----+----+ +----+----+----+----+
| A2 | B2 | C2 | | 2 | A2 | B2 | C2 |
+----+----+----+ +----+----+----+----+
| A3 | B3 | C3 | | 3 | A3 | B3 | C3 |
+----+----+----+ +----+----+----+----+
| A4 | B4 | C4 | | 4 | A4 | B4 | C4 |
+----+----+----+ +----+----+----+----+
| A5 | B5 | C5 | | 5 | A5 | B5 | C5 |
+----+----+----+ +----+----+----+----+
Run Code Online (Sandbox Code Playgroud)
当然,这个想法本身暗示就是用一个redimmednewMatrix作为Dy.Lee提出的,但这将包括两个循环移位的行和列:
Sub test()
Dim matrix As Variant, newMatrix()
Dim i As Long, n As Long, c As Long, j As Long
matrix = Range("A1:C5").Value
n = UBound(matrix, 1)
c = UBound(matrix, 2)
ReDim newMatrix(1 To n, 1 To c + 1)
For i = 1 To n
newMatrix(i, 1) = i
For j = 2 To c + 1
newMatrix(i, j) = matrix(i, j - 1)
Next j
Next i
Range("a1").Resize(n, c + 1) = newMatrix
End Sub
Run Code Online (Sandbox Code Playgroud)
避免不必要循环的另一个工作是将数组写回从 B 列开始的临时工作表,并从那里再次收集数据,包括 A:D 列,但这意味着修改工作表。
Florent B.独自通过使用极快的API 调用解决了这个问题,此后没有其他方法出现。- 因此,出于主要原因,如果这应该是最终比率,或者是否可以找到另一种方法,这会引起一些兴趣。MemCopy
? 修改后的问题(没有重复!)
是否有可能在现有数据字段数组中插入新的第一个“列”
与 Prezmyslaw 的 OP 不同,我没有使用庞大的数据集,因此可以限制大约 64k 行(参见最大转置限制)。
T.M*_*.M. 11
通过Application.Index函数找到解决方案
我通过尝试一些不寻常的Application.Index函数变体找到了一个解决方案,我尝试将其恢复为全面的通用概述,以展示丰富的应用程序范围。因此,欢迎任何有用的补充(参见 @chrisneilsen 的评论)。
Application.Index函数的一些特点
通常,索引函数会通过其行和列位置提供定义明确的项目,但也有一些不那么广为人知的特性:
与该Worksheet.Index函数类似,如果行号或列号参数设置为零 (0),您可以获得整个列或行项目。-可以在如何在 Excel VBA 中初始化二维数组中找到另一种通过传递双零参数来创建二维数组的常见方法
可能使用数组参数- 此函数不仅允许通过给定数字的已知索引指示,还允许数组参数提取“行”或“列”,因此可以指示一组想要的列,例如A:C通过Array(1,2,3)作为列数组参数.
过滤效果- 此外,我了解到可以将选择减少到某些列(行),例如通过Array(1,3) and even to change the internal order, e.g. Array(3,2,1)`。
重组- 然而,最令人惊讶的事实是可以重复列选择,例如通过Array(1,1,2,3)
或什至Array(0,1,2,3)在0项目与列 1 相同的地方。这可用于达到与列插入相同的效果。
这最后的调整能力所提到的Index功能是我的方法的关键部分:
代码示例
Sub AddFirstIndexColumn()
Dim v, i&, ws As Worksheet
Set ws = ThisWorkbook.Worksheets("SourceSheet") ' << change to source sheet name
' [1] get data
v = ws.[A1:C5].Value2
' [2] define column array inserting first column (0 or 1) and preserving old values (1,2,3)
v = Application.Index(v, _
Application.Evaluate("row(1:" & UBound(v) & ")"), _
Array(0, 1, 2, 3)) ' columns array where 0 reinserts the first column
' [3] add an current number in the first column
For i = LBound(v) To UBound(v): v(i, 1) = i: Next i
End Sub
Run Code Online (Sandbox Code Playgroud)
如何测试结果
只需在上面的代码中插入以下内容:
' [4a] test result by debugging in immediate window
For i = LBound(v) To UBound(v)
Debug.Print "#" & i & ": " & Join(Application.Index(v, i, 0), ", ")
Next i
' [4b] test result by writing back to target sheet
Dim ws2 As Worksheet
Set ws2 = ThisWorkbook.Worksheets("TargetSheet") ' << change to target sheet name
ws2.Range("A1").Resize(UBound(v), UBound(v, 2)).Offset(0, 0) = v
Run Code Online (Sandbox Code Playgroud)
警告
找到的解决方案似乎仅限于 65536 行(可能类似于数组转置限制),因此您无法将其用于更大的数据。
最近的一些Application.Index例子