我目前将二维范围读入Excel VBA数组,如下所示:
Set Ws = Sheet1
Ws.Activate
LastRow = Ws.Cells.Find("*", searchorder:=xlByRows, searchdirection:=xlPrevious).Row
LastCol = Ws.Cells.Find("*", searchorder:=xlByColumns, searchdirection:=xlPrevious).Column
ReDim elements(0 To LastRow - 2, 0 To LastCol - 2)
elements = Ws.Range(Cells(2, 1), Cells(LastRow, LastCol))
范围是25行乘11列。但是,并非该范围内的所有单元格都具有值,因此数组中的某些值为“空”'。
我需要遍历这个数组并创建第二个数组,这将是一个"笛卡尔积"来自第一个的值。为了确定我需要循环多少次,我需要弄清楚每个数组列中有多少项("维度"?)。
这是我的循环尝试:
Row = 0
For i = 1 To 25 'numElements in column 1
For j = 1 To 3 'numElements in column 6
For k = 1 To 5 'numElements in column 7
For l = 1 To 14 'numElements in column 8
For m = 1 To 6 'numElements in column 10
For n = 1 To 12 'numElements in column 11
cartesian(Row, 0) = elements(i, 0)
cartesian(Row, 1) = elements(i, 1)
cartesian(Row, 2) = elements(i, 2)
cartesian(Row, 3) = elements(i, 3)
cartesian(Row, 4) = elements(i, 4)
cartesian(Row, 5) = elements(j, 5)
cartesian(Row, 6) = elements(k, 6)
cartesian(Row, 7) = elements(l, 7)
cartesian(Row, 8) = elements(l, 8)
cartesian(Row, 9) = elements(m, 9)
cartesian(Row, 10) = elements(n, 10)
Row = Row + 1
Next n
Next m
Next l
Next k
Next j
Next i
任何帮助表示赞赏:)
编辑1:
这是我读入array1的范围:
Austria sem jan
Belgium gdn feb
France mar
US apr
may
jun
我需要能够计算出多少"项目"第1列,第2列和第3列中有它们相乘。这样我就会知道ReDim第二个数组需要多大。
这就是我在数组2中所需要的,并最终写回另一张表:
Austria sem jan
Austria sem feb
Austria sem mar
Austria sem apr
Austria sem may
Austria sem jun
Austria gdn jan
Austria gdn feb
Austria gdn mar
Austria gdn apr
Austria gdn may
Austria gdn jun
Belgium sem jan
Belgium sem feb
Belgium sem mar
Belgium sem apr
Belgium sem may
Belgium sem jun
Belgium gdn jan
Belgium gdn feb
Belgium gdn mar
Belgium gdn apr
Belgium gdn may
Belgium gdn jun
等
答案 0 :(得分:1)
这应该像你在相当长的时间内需要它一样......仍然需要一些时间来达到~300k的条目:
Option Explicit
Sub getMyList()
'set input
Dim inputVal As Variant
'get input values
With ThisWorkbook.Worksheets("Sheet1")
inputVal = .Range(.Cells(1, 1), .Cells(.Cells.Find("*", , , , 1, 2).Row, .Cells(1, 1).End(xlToRight).Column)).Value
End With
'set count array
Dim xCounts() As Variant
ReDim xCounts(1 To UBound(inputVal, 2))
Dim i As Long, j As Long
For i = 1 To UBound(xCounts)
j = 1
While inputVal(j, i) <> "" And j < UBound(inputVal)
j = j + 1
Wend
'xCounts(i) = j - 1 'will skip last value if it is at the last row
xCounts(i) = j + (inputVal(j, i) = "") 'new one will work as wanted
Next
'set output sizes
Dim outVal() As Variant
ReDim outVal(1 To Application.Product(xCounts), 1 To UBound(xCounts))
'runner sets
Dim colRunner As Long, rowRunner As Long, copyRunner As Long
Dim itemRep As Long, listRep As Long
For colRunner = 1 To UBound(xCounts)
rowRunner = 1
itemRep = 1
listRep = 1
'repeat whole list
For i = 1 To colRunner - 1
listRep = listRep * xCounts(i)
Next
'repeat each item
For i = colRunner + 1 To UBound(xCounts)
itemRep = itemRep * xCounts(i)
Next
'run the list for output
copyRunner = 1
For i = 1 To listRep
For copyRunner = 1 To xCounts(colRunner)
For j = 1 To itemRep
outVal(rowRunner, colRunner) = inputVal(copyRunner, colRunner)
rowRunner = rowRunner + 1
Next
Next
Next
Next
'output everything
ThisWorkbook.Worksheets("Sheet2").Cells(1, 1).Resize(UBound(outVal), UBound(outVal, 2)).Value = outVal
End Sub
代码应该易于阅读(内部没有真正的魔法):P
但是,如果还有任何问题,请问:)
修改强>
xCounter
只保留每列所有项目的计数,因为这些数字被多次使用
澄清一下:我们假设您有一个这样的列表:
A B C D E
1 1 1 1 1
2 2 2 2 2
3 3 3 3
4 4 4
5 5 5
6 6 6
7 7
8
(使用的数字便于计数,也适用于任何字符串)
xCounter现在为{8,2,6,7,3}
。现在,如果您想要记下C列,那么您需要知道每个项目需要重复多少次。这可以通过将稍后出现的所有列的计数相乘来计算。对于这种情况,它将是7 * 3 = 21
次。此外,您需要知道要循环的列表中有多少项6
。然后整个列表也需要重复自己,这可以通过乘以它前面的所有行数来计算。那将是8 * 2 = 16
次。这样也可以构建3个内部For ... Next
循环。 ListRepeat(EachItem(ItemRepeat))
。
要知道要写入输出数组中的哪一行,您需要一个简单的向上计数值,即RowCounter
。直接在工作表中执行此操作,您将使用一个范围,每次在单元格中写入值时,该范围都会向下偏移一行
通过这个系统,你可以将每一列与其他列完全分开,因为你需要的只是前导列和后续列的项目计数的产物(我们有xCounter)。我们仍然需要为每个列执行此操作,因此外部循环是列(colRunner)
只是为了避免因使用i, j, k, l
在彼此内部进行4次循环而感到困惑,我将outVal
中的行的“runner”重命名为rowRunner
,将colRunner
中的行重命名为{{1} }}。将重复的上限和下限直接设置在内环的前面,我留在i
和j
。 (它们也不用于那个循环中的任何东西,它们只是通过多次执行相同的动作来确保重复)
如果我错过了某些内容或其他问题,请执行此操作,因为它总是正确的做法:问。 ;)