zl程序教程

您现在的位置是:首页 >  其他

当前栏目

VBA: 单元格区域基于指定列重新排序(3)

2023-02-18 16:32:47 时间

文章背景:在数据处理时,有时需要根据指定列的内容进行重新排序。比如样品测试时,假设存在5个测试点,其中2号点和3号点无需测,在做报告时,一般会保留2号点和3号点的位置,测试数据为空。

针对排序的步骤,可以通过VBA代码实现。之前提到过两种方法,参见文末的延伸阅读。当数据条不多时,这两种方法的运行时长还可以接受。当数据条有上百条时,运行耗时相对较长。下面借助字典和数组,介绍第三种排序的方法。

代码实现:在原有测试数据的基础上,根据“品号”列和给定的测试点数目(暂定91个),进行重新排序。

Sub sample_sort3()

    '根据品号列重新排序
    
    Dim row_ini As Integer, lastRow As Integer, number As Integer
    Dim name_sample As String, ii As Integer
    Dim sample_temp As String, row_temp As Integer, number_temp As Integer
    Dim obj_range As Range, firstAddress As String
    
    Dim time_ini As Date    '用于计时
    
    Dim col_total As Integer, dic As Object, dic_sample As Object
    
    Dim arrIn As Variant, arrOut As Variant, arrSample As Variant
    
    time_ini = Timer    '计时开始
    
    row_ini = 2     '测试数据从第2行开始 (第1行是标题行)
    
    lastRow = Cells(Rows.Count, 3).End(xlUp).Row   '测试数据最后一行的行号
    
    number = 91  '测试点数目,包括无需测的测试点。
    
    name_sample = "SAM21-123"  '样品名称
    
    col_total = 5       '数据的列数
    
    '字典初始化
    Set dic_sample = CreateObject("scripting.dictionary")      '用于存放序号
    Set dic = CreateObject("scripting.dictionary")             '用于判断点号是否已测
    
    ReDim arrOut(1 To number, 1 To col_total)
    
    ReDim arrSample(1 To number, 1 To 1)
    
    '字典序号
    For ii = 1 To number
    
        sample_temp = name_sample & "-" & CStr(ii)
        
        '使用字典储存样品点的顺序号
        dic_sample(sample_temp) = ii
        
        '使用数组存储样品点
        arrSample(ii, 1) = sample_temp
    
    Next ii
    
    '将测试数据拷贝到临时数组,减少VBA与表格的交互
    With ActiveSheet
    
        arrIn = .Range(.Cells(1, 1), .Cells(lastRow, 6)).Value2
        
    End With
    
    With ActiveSheet.Columns(3)
    
        Set obj_range = .Find(What:=name_sample, After:=Cells(2, 3), LookIn:=xlFormulas, _
                        LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
                        MatchCase:=False, MatchByte:=False, SearchFormat:=False)
                    
        If Not obj_range Is Nothing Then
    
            firstAddress = obj_range.Address
            
            Do
                sample_temp = obj_range.Value2
                
                row_temp = obj_range.Row
                
                number_temp = dic_sample(sample_temp)   '顺序号
                
                For ii = 2 To 6
                    
                    arrOut(number_temp, ii - 1) = arrIn(row_temp, ii)
                
                Next ii
                
                '记录已测的点号
                dic(sample_temp) = True
                      
                Set obj_range = .FindNext(obj_range)
                
            Loop While Not obj_range Is Nothing And obj_range.Address <> firstAddress
    
        End If
    
    End With
    
    '将数组拷贝到指定区域
    If dic.Count > 0 Then
    
        '清空旧区域
        Range("B2:F" & lastRow).ClearContents
        
        Range("B2").Resize(number, col_total) = arrOut
        
        Range("C2").Resize(number, 1) = arrSample
    
    End If
    
    MsgBox "Done!  " & vbCrLf & vbCrLf & "用时:" & Format(Timer - time_ini, "0.0s")

    Exit Sub

End Sub

运行效果:http://mpvideo.qpic.cn/0b2eriaagaaapmao7uianvrvbcwdaofaaaya.f10002.mp4?dis_k=c9a360481cd2c7e3e4bfeac3cde0db00&dis_t=1671335557&play_scene=0&vid=wxv_2540284762230505472&format_id=10002&support_redirect=0&mmversion=false