我试图根据“A-O”列中找到的副本来总结值。我使用下面的宏。有大约500k +记录,下面的宏挂起来很糟糕。
Sub Formulae(TargetCol1, TargetCol2, ConcatCol, Col1, Col2, StartRow, EndRow, Sheet)
Sheets(Sheet).Range(TargetCol1 & CStr(StartRow)).Formula = "=SUMIF($" & ConcatCol & "$" & CStr(StartRow) & ":$" & ConcatCol & "$" & CStr(EndRow) & "," & ConcatCol & CStr(StartRow) & ",$" & Col1 & "$" & CStr(StartRow) & ":$" & Col1 & "$" & CStr(EndRow) & ")"
Sheets(Sheet).Range(TargetCol1 & CStr(StartRow)).Select
Selection.Copy
Sheets(Sheet).Range(TargetCol1 & CStr(EndRow)).Select
Range(Selection, Selection.End(xlUp)).Select
Application.CutCopyMode = False
Selection.FillDown
Call PasteSpecial(TargetCol1, "T", StartRow, EndRow)
Sheets(Sheet).Range(TargetCol2 & CStr(StartRow)).Formula = "=SUMIF($" & ConcatCol & "$" & CStr(StartRow) & ":$" & ConcatCol & "$" & CStr(EndRow) & "," & ConcatCol & CStr(StartRow) & ",$" & Col2 & "$" & CStr(StartRow) & ":$" & Col2 & "$" & CStr(EndRow) & ")"
Sheets(Sheet).Range(TargetCol2 & CStr(StartRow)).Select
Selection.Copy
Sheets(Sheet).Range(TargetCol2 & CStr(EndRow)).Select
Range(Selection, Selection.End(xlUp)).Select
Application.CutCopyMode = False
Selection.FillDown
Call PasteSpecial(TargetCol2, "U", StartRow, EndRow)
End Sub
Sub PasteSpecial(Col1, Col2, StartRow, EndRow)
Range(Col1 & CStr(StartRow)).Select
Range(Selection, Selection.End(xlDown)).Select
Selection.Copy
Range(Col2 & CStr(StartRow)).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End Sub
让我简单解释一下这个宏。我有列“A-O”,我必须对它们进行分组......基于分组,我必须对“P,Q”列进行求和。我有一个函数,它在16列中生成一个连接的字符串,并存储在“AA”列中。基于此列,我使用sumif函数对所有重复值进行求和
=SUMIF($AA$2:$AA$500000,$AA2,$P$2:$P$500000)
=SUMIF($AA$2:$AA$500000,$AA2,$Q$2:$Q$500000)
然后我将上面的值复制粘贴为'值'以删除公式,在2个新的cols中(上面的宏代码中的pasteSpecial函数)。
最后,我调用删除重复项来删除重复值
我使用了.removeduplicates方法,即使在如此庞大的数据集上,它似乎也能很快地运行。 excel中是否有任何预定义的函数,它甚至可以对重复项的值求和,然后删除重复的条目?
Sub Remove_Duplicates_In_A_Range(StartRow, EndRow, Sheet, StartCol, EndCol, level)
Sheets(Sheet).Range(StartCol & CStr(StartRow) & ":" & EndCol & CStr(EndRow)).RemoveDuplicates Columns:=20, Header:=xlNo
End Sub
上面的逻辑很糟糕地吃了所有的CPU资源并且崩溃严重......
有人请优化上面的宏,使其适用于500k +记录。最多1-2分钟的表现是可以接受的。
请帮助!!!
编辑:按500k +记录我的意思是A1:O500000。我应该以这种方式检查重复,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1与A2,B2,C2,D2的组合, E2,F2,G2,H2,I2,J2,K2,L2,M2,N2,O2和A3,B3,C3,D3,E3,F3,G3,H3,I3,J3,K3,L3,M3,N3, O3等......直到A500000,B500000等......
总之我应该检查整个A1-O1套装与整个A2-O2或A3-O3或...... A500k-O500k匹配等等
对于整个A-O记录集之间的每个匹配,我需要将它们各自的P,Q列相加。比如A1-O1设置与A2-O2设置匹配然后添加P1,Q1和P2,Q2并存储在P1,Q1或其他东西..
在任何一种情况下,我都需要保留每个原始记录集,例如A1-O1,其副本的总和值和自己在P1,Q1中的总和
我不认为我们现在可以在这里附上excel表的演示,是吗? :(
EDIT2:
在所有细胞中复制sumif公式的功能
Sub PreNettingBenefits(StartRow1, EndRow1, StartRow2, EndRow2, Col_Asset, Col_Liab, Src_Col_Asset, Src_Col_Liab, ConcatCol, Src_ConcatCol, level, Sheet2, Sheet1)
'=SUMIF(Sheet1!$AA$2:$AA$81336,Sheet2!AA2,Sheet1!$P$2:$P$81336)
Application.Calculation = xlCalculationAutomatic
Sheets(Sheet2).Range(Col_Asset & CStr(StartRow2)).Formula = "=SUMIF(" & Sheet1 & "!$" & Src_ConcatCol & "$" & CStr(StartRow1) & ":$" & Src_ConcatCol & "$" & CStr(EndRow1) & "," & Sheet2 & "!" & ConcatCol & CStr(StartRow2) & "," & Sheet1 & "!$" & Src_Col_Asset & "$" & CStr(StartRow1) & ":$" & Src_Col_Asset & "$" & CStr(EndRow1) & ")"
Sheets(Sheet2).Range(Col_Asset & CStr(StartRow2)).Select
Selection.Copy
MsgBox Sheets(Sheet2).Range(Col_Asset & CStr(EndRow2)).Address
Sheets(Sheet2).Range(Col_Asset & CStr(EndRow2)).Select
Range(Col_Asset & CStr(StartRow2) & ":" & Col_Asset & CStr(EndRow2)).Select
Application.CutCopyMode = False
Selection.FillDown
Sheets(Sheet2).Range(Col_Liab & CStr(StartRow2)).Formula = "=SUMIF(" & Sheet1 & "!$" & Src_ConcatCol & "$" & CStr(StartRow1) & ":$" & Src_ConcatCol & "$" & CStr(EndRow1) & "," & Sheet2 & "!" & ConcatCol & CStr(StartRow2) & "," & Sheet1 & "!$" & Src_Col_Liab & "$" & CStr(StartRow1) & ":$" & Src_Col_Liab & "$" & CStr(EndRow1) & ")"
Sheets(Sheet2).Range(Col_Liab & CStr(StartRow2)).Select
Selection.Copy
MsgBox Sheets(Sheet2).Range(Col_Liab & CStr(EndRow2)).Address
Sheets(Sheet2).Range(Col_Liab & CStr(EndRow2)).Select
Range(Col_Liab & CStr(StartRow2) & ":" & Col_Liab & CStr(EndRow2)).Select
Application.CutCopyMode = False
Selection.FillDown
Application.Calculation = xlCalculationManual
End Sub
它很糟糕。解决了在30k-40k行中复制公式的问题。有人可以优化代码吗?
答案 0 :(得分:3)
对于如何添加重复项,必定会出现严重错误。由于您对所使用数据的详细信息不足,我不知道这是否相同,但我填写了A1:O33334(超过500k的单元格),随机数介于1到10,000之间。
使用字典对象(我以我的爱和过度使用而闻名),我浏览了所有这些并仅将重复值相加,然后将唯一的元素列表打到了Sheet2中的A列。
为什么要使用字典的原因:
欺骗检查和添加以及复制唯一单元仅需2秒。以下是供您参考的代码。
Sub test()
Application.ScreenUpdating = False
Dim vArray As Variant
Dim result As Long
Dim dict As Object
Set dict = CreateObject("scripting.dictionary")
vArray = Range("A1:O33334").Value
On Error Resume Next
For i = 1 To UBound(vArray, 1)
For j = 1 To UBound(vArray, 2)
If dict.exists(vArray(i, j)) = False Then
dict.Add vArray(i, j), 1
Else
result = result + vArray(i, j)
End If
Next
Next
Sheet2.Range("a1").Resize(dict.Count).Value = _
Application.Transpose(dict.keys)
Application.ScreenUpdating = True
MsgBox "Total for duplicate cells: " & result & vbLf & _
"Unique cells copied: " & dict.Count
End Sub
答案 1 :(得分:2)
执行代码时,不应该select
每个单元格。
顺便说一下,如果你看一下你的代码,一些陈述是没用的:
Sheets(Sheet).Range(TargetCol1 & CStr(StartRow)).Select
Selection.Copy
永远不会粘贴
有关性能问题,请参阅此主题中的一些提示:Benchmarking VBA Code
答案 2 :(得分:1)
根据我的理解,问题的实质是找到重复项并将其添加,然后删除它们。你还提到了对它们进行分组,但目前还不清楚如何。无论如何,我会放弃宏。单个行的操作不适用于该数据集。
以下是我要采取的一些步骤。修改它们以满足您的需求:
使用连接功能在数据集右侧创建新列。例如
=concatenate(a2,b2,c2,d2,e2)
创建一个名为Dups的列,并使用以下内容填充它:
=if(countif(dataSetNamedRange,aa2)>1,1,0)
在上面的代码中,aa2指的是该行的连接列。上述结果是您现在标记了所有重复项。现在使用“数据”菜单中的过滤器工具创建排序或过滤器以满足您的分组需求。要添加值,请使用DSum。要删除重复项,请使用高级过滤器。祝你好运。
答案 3 :(得分:0)
我将此作为第二个答案添加,因为它会变得很长......
因为我是一个顽固的骡子,我尝试了很多不同的东西,我认为你已经达到了Excel可以做的极限。我能想到的最好的功能就是这个,注意我使用了50,000行,而不是你的500,000:
如您所见,随着唯一行数的增加,函数将会恶化。我在这里有很多古怪的想法,所以我想我会为了研究而分享我的代码:
Sub test()
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Dim rowArray As Variant
Dim totalArray As Variant
Dim i As Long, j As Long
Dim dupeDict As Object
Set dupeDict = CreateObject("scripting.dictionary")
Dim count As Long
Dim rowData() As String
'dump the cells into an single array
rowArray = Range("A1:O50000").Value
'grab totals from P and Q to keep them seperate
totalArray = Range("P1:Q50000").Value
'create strings for each row
ReDim rowData(1 To 50000)
'create a string for each row
For i = 1 To 50000
For j = 1 To 15
rowData(i) = rowData(i) & rowArray(i, j)
Next
Next
'free up that memory
Set rowArray = Nothing
'check all rows, total P & Q if match
On Error Resume Next
For i = 1 To 50000
'skip row and move to next if we've seen it
If dupeDict.exists(i) = True Then
GoTo Dupe
End If
count = 0
For j = 1 To 50000
If rowData(i) = rowData(j) Then
dupeDict.Add j, 1 'add that sucker to the dupe dict
count = count + totalArray(j, 1) + totalArray(j, 2)
End If
'enter final total in column R
Cells(i, 18).Value = count
Next
Dupe:
Next
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub