Non-Intersect Range VBA

后端 未结 3 1118
太阳男子
太阳男子 2020-12-20 20:52

In the below code rngIntersect.Address returns A10. Is there way where in i can get all ranges excluding intersection without looping?



        
相关标签:
3条回答
  • 2020-12-20 21:19

    As far as I know there is no "clean" function for this. If the requirement "no looping" is important, you could try the following (this is an "approach", not working code):

    - create a new sheet
    - find intersection of ranges
    - set range from top left to bottom right of intersection to 0
    - set range1 to 1
    - set all values in range2 = XOR of values that are there (so 1 becomes 0, and 0 becomes 1)
    - find all cells with a 1 - their address is the "non-intersection"
    - delete the temp sheet
    

    I believe each of these can be done without a loop - but it's a terrible hack...

    0 讨论(0)
  • 2020-12-20 21:23

    I had posted this question to msdn forum with lack of response from SO and got the required solution. I have tested the code and it works fine. I hope it helps.

    Here is the link for post on msdn.

    Sub NotIntersect()
            Dim rng As Range, rngVal As Range, rngDiff As Range
            Set rng = Range("A1:A10")
            Set rngVal = Range("A5")
            Set rngDiff = Difference(rng, rngVal)
            MsgBox rngDiff.Address
        End Sub
    
        Function Difference(Range1 As Range, Range2 As Range) As Range
            Dim rngUnion As Range
            Dim rngIntersect As Range
            Dim varFormulas As Variant
            If Range1 Is Nothing Then
                Set Difference = Range2
            ElseIf Range2 Is Nothing Then
                Set Difference = Range1
            ElseIf Range1 Is Nothing And Range2 Is Nothing Then
                Set Different = Nothing
            Else
                Set rngUnion = Union(Range1, Range2)
                Set rngIntersect = Intersect(Range1, Range2)
                If rngIntersect Is Nothing Then
                    Set Difference = rngUnion
                Else
                    varFormulas = rngUnion.Formula
                    rngUnion.Value = 0
                    rngIntersect.ClearContents
                    Set Difference = rngUnion.SpecialCells(xlCellTypeConstants)
                    rngUnion.Formula = varFormulas
                End If
            End If
        End Function
    
    0 讨论(0)
  • 2020-12-20 21:31

    What you're looking for is the "Complement" in Set Theory terminology. See Wikipedia. This can be done without looping through every cell in both ranges (that would be a huge overhead for ranges with many cells), but you will need to loop though each Area within the range. That loop is quick and efficient. Here's the code:

    Public Function NotIntersect(Range1 As Range, Range2 As Range) As Range
    Dim NewRange As Range, CurrentArea As Range, CurrentNewArea(1 To 4) As Range, r As Range
    Dim c%, a%
    Dim TopLeftCell(1 To 2) As Range, BottomRightCell(1 To 2) As Range
    Dim NewRanges() As Range, ColNewRanges() As New Collection
    Const N% = 2
    Const U% = 1
    
    If Range1 Is Nothing And Range2 Is Nothing Then
        Set NotIntersect = Nothing
    ElseIf Range1.Address = Range2.Address Then
        Set NotIntersect = Nothing
    ElseIf Range1 Is Nothing Then
        Set NotIntersect = Range2
    ElseIf Range1 Is Nothing Then
        Set NotIntersect = Range1
    Else
    
        Set TopLeftCell(U) = Range1.Cells(1, 1)
        Set BottomRightCell(U) = Range1.Cells(Range1.Rows.Count, Range1.Columns.Count)
    
        c = Range2.Areas.Count
        ReDim ColNewRanges(1 To c)
        ReDim NewRanges(1 To c)
    
        For a = 1 To c
            Set CurrentArea = Range2.Areas(a)
            Set TopLeftCell(N) = CurrentArea.Cells(1, 1)
            Set BottomRightCell(N) = CurrentArea.Cells(CurrentArea.Rows.Count, CurrentArea.Columns.Count)
    
            On Error Resume Next
            Set ColNewRanges(a) = New Collection
            ColNewRanges(a).Add Range(TopLeftCell(U), Cells(TopLeftCell(N).Row - 1, BottomRightCell(U).Column))
            ColNewRanges(a).Add Range(Cells(TopLeftCell(N).Row, TopLeftCell(U).Column), Cells(BottomRightCell(N).Row, TopLeftCell(N).Column - 1))
            ColNewRanges(a).Add Range(Cells(TopLeftCell(N).Row, BottomRightCell(N).Column + 1), Cells(BottomRightCell(N).Row, BottomRightCell(U).Column))
            ColNewRanges(a).Add Range(Cells(BottomRightCell(N).Row + 1, TopLeftCell(U).Column), BottomRightCell(U))
            On Error GoTo 0
    
            For Each r In ColNewRanges(a)
                If NewRanges(a) Is Nothing Then
                    Set NewRanges(a) = r
                Else
                    Set NewRanges(a) = Union(NewRanges(a), r)
                End If
            Next r
    
        Next a
    
        For a = 1 To c
            If NewRange Is Nothing Then
                Set NewRange = NewRanges(a)
            Else
                Set NewRange = Intersect(NewRange, NewRanges(a))
            End If
        Next a
    
        Set NotIntersect = Intersect(Range1, NewRange) 'intersect required in case it's on the bottom or right line, so a part of range will go beyond the line...
    
    End If    
    End Function
    

    Test is as follows:

    Sub Test1()
        NotIntersect(Range("$A$1:$N$24"), Range("$G$3:$H$12,$C$4:$D$7,$A$13:$A$15")).Select
    End Sub
    
    0 讨论(0)
提交回复
热议问题