Excelmacrosarrays
目前我有一个macros,通过列表运行并删除重复值(在一列中),但它被certificate是非常低效的。 对于每一个检查重复的条目,它都必须贯穿整个列; 我的文件目前有50,000个条目,这不是一个小任务。
我认为macros工作的一个更简单的方法是macros来检查这个值是否在一个数组中。 如果是,则删除条目所在的行。如果不是,则将该值添加到数组中。
有人可以提供一些macros的基本纲要的帮助吗? 谢谢
下面的代码将遍历你的源数据并将其存储在一个数组中,同时检查重复项。 收集完成后,它使用该数组作为关键字来知道要删除哪些列。
由于删除的电位器屏幕更新数量很高,请务必closures屏幕更新。 (附带)
Sub Example() Application.ScreenUpdating = false Dim i As Long Dim k As Long Dim StorageArray() As String Dim iLastRow As Long iLastRow = ActiveSheet.Cells(ActiveSheet.Rows.Count, "A").End(xlUp).Row ReDim StorageArray(1 To iLastRow, 0 To 1) 'loop through column from row 1 to the last row For i = 1 To iLastRow 'add each sheet value to the first column of the array StorageArray(i, 0) = ActiveSheet.Range("A" & i).Value '- keep the second column as 0 by default StorageArray(i, 1) = 0 '- as each item is added, loop through previously added items to see if its a duplicate For k = 1 To i-1 If StorageArray(k, 0) = StorageArray(i, 0) Then 'if it is a duplicate set the second column of the srray to 1 StorageArray(i, 1) = 1 Exit For End If Next k Next i 'loop through sheet backwords and delete rows that were maked for deletion For i = iLastRow To 1 Step -1 If StorageArray(i, 1) = 1 Then ActiveSheet.Range("A" & i).EntireRow.Delete End If Next i Application.ScreenUpdating = true End Sub
按照要求,这里有一个类似的方法,使用Collections而不是Array来进行键索引:(RBarryYoung)
Public Sub RemovecolumnDuplicates() Dim prev as Boolean prev = Application.ScreenUpdating Application.ScreenUpdating = false Dim i As Long, k As Long Dim v as Variant, sv as String Dim cl as Range, ws As Worksheet Set ws = ActiveWorksheet 'NOTE: This really should be a parameter ... Dim StorageArray As New Collection Dim iLastRow As Long iLastRow = ws.Cells(ActiveSheet.Rows.Count, "A").End(xlUp).Row 'loop through column from row 1 to the last row i = 1 For k = 1 To iLastRow 'add each sheet value to the collection Set cl = ws.Cells(i, 1) v = cl.Value sv = Cstr(v) On Error Resume Next StorageArray.Add v, sv If Err.Number <> 0 Then 'must be a duplicate, remove it cl.EntireRow.Delete 'Note: our index doesn't change here, since all of the rows moved Else 'not a duplicate, so go to the next row i = i + 1 End If Next k Application.ScreenUpdating = prev End Sub
请注意,此方法不需要为列中单元格的值假设任何数据types或整数限制。
(Mea Culpa:我必须在记事本中手工input,因为我的Excel正在忙于正在运行的项目testing,所以可能会有一些拼写/语法错误…)
这是我的评论的后续。 循环50klogging + 循环arrays将是这样一个简单的操作过度杀死。
就像我在我的评论中提到的那样,将数组中的值复制到新的工作表中。 然后在50k条目旁边插入一个空白列,然后做一个Vlookup
或CountIf
。 完成后,执行一次自动筛选,然后删除重复项。 我们来举个例子,看看这个如何工作。
假设我们有一个有1000个项目的数组? 在一页中我们有50k的数据。 下面的代码将1000 items in Array
和50k Data
使用1000 items in Array
进行testing请参阅快照
将这段代码粘贴到一个模块中( 代码花费less于5秒完成 )
Sub Sample() Dim ws As Worksheet, wstemp As Worksheet Dim LRow As Long Dim Ar(1 To 1000) As Long Dim startTime As String, EndTime As String startTime = Format(Now, "hh:mm:ss") Set ws = Sheets("Sheet1") Set wstemp = Sheets.Add '~~> Creating a dummy array For i = 1 To 1000 Ar(i) = i Next i '~~> Copy it to the new sheet wstemp.Range("A1:A1000").Value = Application.Transpose(Ar) With ws LRow = .Range("A" & .Rows.Count).End(xlUp).Row .Columns(2).Insert Shift:=xlToRight .Range("B1").Value = "For Deletion" .Range("B2:B" & LRow).FormulaR1C1 = "=COUNTIF(" & wstemp.Name & "!C[-1],RC[-1])" .Columns(2).Value = .Columns(2).Value '~~> Remove any filters .AutoFilterMode = False '~~> Filter, offset(to exclude headers) and delete visible rows With .Range("B1:B" & LRow) .AutoFilter Field:=1, Criteria1:="<>0" .Offset(1, 0).SpecialCells(xlCellTypeVisible).EntireRow.Delete End With '~~> Remove any filters .AutoFilterMode = False .Columns(2).Delete End With EndTime = Format(Now, "hh:mm:ss") MsgBox "The process started at " & startTime & " and finished at" & EndTime End Sub
对于Excel 2007及更高版本:将数组复制到工作表并使用removeduplicates方法:
set ws = worksheets.add ws.[A1].resize(ubound(yourarray,1),ubound(yourarray,2)).value = yourarray ws.usedrange.removeduplicates columns:=1, header:=no
这假定您的数组的下限是1,您要重复的列是列1,并且您的列表没有标题。 然后,您可以find新范围的边界并将其读回您的数组(先擦除当前数组)。
我会build议填充你的列,然后使用公式来find重复项并删除它们。 我没有真正的代码给你(你没给我们任何代码)
dim a as range dim b as range set a = Range ("A1") Do while Not isEmpty(A) Set b = a.offset(1,0) If b = a then b= "" else a.offset (1,0) Loop
我相信你可以把filter放在代码中,或者在运行macros之前重新填充。