非相交范围 VBA
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16328551/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Non-Intersect Range VBA
提问by Santosh
In the below code rngIntersect.Address
returns A10
. Is there way where in i can get all ranges excluding intersection without looping?
在下面的代码中rngIntersect.Address
返回A10
. 有没有办法让我可以在不循环的情况下获得不包括交集的所有范围?
Thanks
谢谢
Sub NotIntersect()
Dim rng As Range, rngVal As Range, rngIntersect As Range
Set rng = Range("A1:A10")
Set rngVal = Range("A10")
Set rngIntersect = Intersect(rng, rngVal)
MsgBox rngIntersect.Address
End Sub
采纳答案by Santosh
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.
我已将此问题发布到 msdn 论坛,但没有得到 SO 的回应,并获得了所需的解决方案。我已经测试了代码,它工作正常。我希望它有帮助。
Here is the linkfor post on msdn.
这是在 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
回答by as9876
What you're looking for is the "Complement" in Set Theory terminology. See Wikipedia. This canbe 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:$N"), Range("$G:$H,$C:$D,$A:$A")).Select
End Sub
回答by Floris
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...
我相信这些都可以在没有循环的情况下完成 - 但这是一个可怕的黑客......