Arrays Excel VBA-在无循环或API调用的数据字段数组中插入新的第一列
简介 去年@PrzemyslawRemin在没有附加循环的情况下提出了这个问题,并且在没有修改工作表的情况下提出了这个问题 本例中的原始矩阵是一个(基于1的2维)数据字段数组,其结果是(源单元格仅包含其地址字符串;插入的行用数字填充) 输入矩阵:-------------▼ 期望的结果:Arrays Excel VBA-在无循环或API调用的数据字段数组中插入新的第一列,arrays,vba,excel,matrix,Arrays,Vba,Excel,Matrix,简介 去年@PrzemyslawRemin在没有附加循环的情况下提出了这个问题,并且在没有修改工作表的情况下提出了这个问题 本例中的原始矩阵是一个(基于1的2维)数据字段数组,其结果是(源单元格仅包含其地址字符串;插入的行用数字填充) 输入矩阵:-------------▼ 期望的结果: +----+----+----+ +----+----+----+----+ | A1 | B1 | C1 | | 1 | A1 | B1 | C1 | +----+----+----+ +
+----+----+----+ +----+----+----+----+
| 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 |
+----+----+----+ +----+----+----+----+
当然,建议自己的想法是使用Dy.Lee提出的重新命名的newMatrix
,但这将包括两个循环来移动行和列:
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
另一个解决办法是避免不必要的循环,即从B列开始将数组写回临时工作表,并从B列收集数据,包括a:D列,但这意味着修改工作表
Florent B.单独使用MemCopy
通过极快的API调用来解决问题,此后似乎没有其他方法。-因此,出于主要原因,如果这应该是最终比率,或者如果可以找到另一种方法,则会引起一些兴趣
► 已修改的问题(无重复!)
是否有可能在现有数据字段数组中插入新的第一个“列”
- 不在“行”和“列”上循环以移动现有值
- 无需修改工作表和
- 没有使用VBA的API调用李>
与Prezmyslaw的OP不同,我没有使用庞大的数据集,因此可以限制大约64k行(c.f.最大转置限制)。通过
应用程序。Index
函数找到解决方案
我找到了一个解决方案,只是尝试了应用程序的一些不寻常的变体。Index
函数,我尝试将其恢复为一个全面的通用概述,以展示丰富的应用程序范围。因此,欢迎任何有用的补充(c.f.@chrisneilsen的评论)
应用程序索引的一些特性函数
通常,索引函数会根据其行和列位置提供定义良好的项,但有一些不太为人所知的特性:
工作表.Index
函数类似,如果row或column number参数设置为零(0),则可以获取整个列或行项目通过传递双零参数创建二维阵列的另一种常见未知方法可以在
数组(1,2,3)
作为列数组参数指示所需的列集,例如a:C
数组(1,3),甚至可以更改内部顺序,例如数组(3,2,1)`
数组(1,1,2,3)
甚至是数组(0,1,2,3)
,其中0
项与第1列相同。这可用于达到与列插入相同的效果
索引
功能的最后一个重组功能是我方法的关键部分:
代码示例
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
子AddFirstIndexColumn()
尺寸v、i和ws作为工作表
设置ws=ThisWorkbook.Worksheets(“SourceSheet”)供参考使用索引的方法很有趣,但对于此应用程序,它明显比循环方法或API方法慢。循环运行的时间约为一半,API运行的时间约为一半(在10000行范围内进行了测试)。FWIW,我知道你将Q框定为“没有附加循环…”,但依我看,这是一个没有价值的任意约束。如果代码需要在mac上运行,则排除API调用是有效的。感谢您宝贵的反馈。我完全同意你的观点,即当更大的数据集的时间至关重要时,循环是无与伦比的。-出于好奇和艺术的缘故,我在这里的目的是丰富传统解决方案。在通过实验深入了解索引的特殊性时,我发现了一个真正的重构可能性宝库,我试图将其列为有用的一般概述。因此,欢迎任何像您这样有帮助的补充@chrisneilsenAs对API方法的看法:我故意排除了我在原始帖子中特别提到的API调用,因为在我看来,它已经得到了一定的限制然而,我正在考虑提出一个新的、扩展的问题,重点是API问题:-)@chrisneilsen
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
' [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