【问题标题】:Working with arrays in VBA memory and avoiding loops using vectorization使用 VBA 内存中的数组并使用矢量化避免循环
【发布时间】:2014-07-23 21:10:56
【问题描述】:

我精通 MATLAB,但最近发现自己在 VBA 中工作,因为我不太容易使用 MATLAB,而且我努力尝试在 VBA 中做一些我可以在 MATLAB 中轻松处理的事情(如矢量化)。

假设我有一个以下形式的 excel 数据表:

record  startDate   endDate count
1   100 103 10
2   98  102 5
3   101 104 4

我想在内存中进行所有处理(避免循环),然后输出如下所示的结果文件:

    1   2   3   Sum
98  0   5   0   5
99  0   5   0   5
100 10  5   0   15
101 10  5   4   19
102 10  5   4   19
103 10  0   4   14
104 0   0   4   4

基本上,我从最早的日期开始,遍历最晚的日期,然后检查每个日期是否包含在每条记录的日期窗口中,如果是,我将记录计数应用于当天,然后将它们相加.

我使用一个简单的工作表函数创建了包含的输出,但我希望能够在 VBA 中复制该过程,特别是避免循环至少减少到 1 个循环而不是嵌入式循环。

如果我在 MATLAB 中我会找到满足条件的逻辑数组,例如:

numDays = 7;
numRecords = 3;
startDate = [100; 98; 101];
endDate = [103; 102; 104];
dateVector = [98; 99; 100; 101; 102; 103; 104];
count = [10; 5; 4];
dateLogic = logical(numDays,numRecords);
for d = 1:numDays
  dateLogic(d,:) = dateVector(d) >= startDate(:,1) &  dateVector(d) <= endDate(:,1)
end
countMatrix = dateLogix * count';
Sum = sum(countMatrix,2);

这将为我提供一个由 0 和 1 组成的逻辑矩阵,我可以将其与计数向量相乘以得到我的计数并最终得到我的 Sum 向量。我相信我什至可以在几天内使用 bsxfun 来消除循环。

请原谅任何潜在的语法错误,因为我现在无法访问 MATLAB。

无论如何,我怎样才能在 VBA 中做类似的事情。是否有等效的冒号表示法来引用数组中的整个列或行范围。我将应用于大型数据集,因此效率至关重要。在粘贴之前我可以在内存中做的越多越好。

提前致谢。

【问题讨论】:

  • 您需要使用一些自定义函数来对数组进行切片。使用二维矩阵数组很容易构建GetRow 函数或GetColumn 函数。这里还有很多有用的辅助函数:www.cpearson.com/excel/array.htm
  • 两个很好的线索,虽然我想避免学习另一种语言(八度)。提供的链接上的数组函数有可能支持我所需要的。

标签: arrays matlab vba vectorization


【解决方案1】:

这是一种可能性,请尝试使用新工作簿的 A1:A4 中的示例数据。

Sub NewTable()

Set Table = Sheet1.[a2:d4]

With Application

    Record = .Transpose(.Index(Table, , 1))
    FirstDate = .Transpose(.Index(Table, , 2))
    LastDate = .Transpose(.Index(Table, , 3))
    Count = .Transpose(.Index(Table, , 4))

    Dates = .Evaluate("row(" & .Min(FirstDate) & ":" & .Max(LastDate) & ")")
    Values = .PV(, Count, .PV(, .GeStep(Dates, FirstDate), .GeStep(LastDate, Dates)))
    Sum = .MMult(Values, .Power(.Transpose(Record), 0))

End With

Sheet1.[F1].Offset(, 1).Resize(, UBound(Values, 2)) = Record
Sheet1.[F2].Resize(UBound(Dates)) = Dates
Sheet1.[G2].Resize(UBound(Values), UBound(Values, 2)) = Values
Sheet1.[G2].Offset(, UBound(Values, 2)).Resize(UBound(Dates)) = Sum

End Sub

【讨论】:

    猜你喜欢
    • 2011-05-24
    • 1970-01-01
    • 2020-12-01
    • 2018-12-27
    • 1970-01-01
    • 2017-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多