Страницы: 1
RSS
Как получить из 2-х пересекающихся диапазонов непересекающиеся части?, Есть ли в VBA функция, обратная Intersect
 
Диапазон А пересекается с диапазоном Б (см. скрин).
Как получить непересекающиеся части?
То есть, если имеется:
Код
Dim x As Range, y As Range
Set x = Range("B3:D6")
Set y = Range("C5:F7")
Как получить покрашенную на желтый цвет диапазон? (см.скрин)
 
Здравствуйте, Бахтиёр! Посмотрите это сообщение.
Владимир
 
Бахтиёр, приветствую!
Функции, обратной Intersect'у, увы, нет  :(
Когда-то и я задавался похожим вопросом  ;)

Если учесть ограничение "нельзя изменять эти диапазоны" (менять цвет, вставлять значения и так далее), то я бы взял в словарь адреса пересечения диапазонов и потом в цикле пробежал по обоим, вычёркивая "словарные" адреса
Можно ускорить (но и усложнить) это процесс, заменив адреса на координаты
Полученные адреса "слеплять" Union'ом (и вообще часто его вызывать где-либо) крайне не рекомендую по причине жесточайшей медлительности (даже с учётом полной его оптимизации)

Если ограничения нет, то тут фантазия поболе вариантов может накинуть (и, скорее всего, пошустрее), но "в жизни" это будет малоприменимо

UPD: Владимир маленько опередил со ссылкой  :D
Изменено: Jack Famous - 14.10.2021 13:05:12
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
sokol92, Jack Famous, спасибо, понятно.
 
Как вариант.
Код
Sub test()
    Dim x As Range, y As Range
    Set x = Range("B3:D6")
    Set y = Range("C5:F7")
    
    RangeDif(x, y).Select
End Sub

Function RangeDif(r1 As Range, r2 As Range) As Range
    Application.ScreenUpdating = False
    Dim wb As Workbook
    Set wb = Workbooks.Add(1)
    With wb.Sheets(1)
        .Range(r1.Address(0, 0)).Value = 1
        .Range(r2.Address(0, 0)).Value = 1
        On Error Resume Next
        Intersect(.Range(r1.Address(0, 0)), .Range(r2.Address(0, 0))).Clear
        On Error GoTo 0
        Dim r As Range
        Set r = .Cells.SpecialCells(xlCellTypeConstants)
    End With
    
    Set RangeDif = r1.Parent.Range(r.Address(0, 0))
    wb.Close False
    Application.ScreenUpdating = True
End Function
 
МатросНаЗебре, спасибо.
 
Можно так
Код
Sub dfdfdf()
Dim x As Range, y As Range, Rng As Range
Set x = Range("B3:D6")
Set y = Range("C5:F7")
    For Each r In Application.Union(x, y)
        If Application.Intersect(r, Application.Intersect(x, y)) Is Nothing Then
            If Rng Is Nothing Then Set Rng = r Else Set Rng = Union(Rng, r)
        End If
    Next r
Rng.Select
MsgBox Rng.Address
End Sub
 
Msi2102, спасибо.
 
Господа, я как бы в VBA вообще никак, но такую штуку Эксель умеет сам считать через УФ, схема такая:
На правах бреда:
Создаем любое правило УФ, которое должно действовать в диапазоне =$B$3:$D$6;$C$5:$F$7
Далее я так понимаю Intersect'ом можно легок вычислить пересечение диапазонов, так вот нужно вырезать этот диапазон ячеек и вставить куда-нибудь на другой лист, и в адресе правила УФ как раз сформируется нужный диапазон автоматически, останется только оттуда его забрать и по удалять те правила, которые создались при вырезании/вставке.
Не знаю на сколько такое костыльное решение будет быстро работать в VBA, но тем не менее какое есть. Спасибо за внимание.
Изменено: PooHkrd - 14.10.2021 13:36:15
Вот горшок пустой, он предмет простой...
 
запустите Test на чистом листе
(BaseModOut выкидывает из базового адреса, OutAdr)
Код
Sub Test()
  Dim rg1, rg2, intrsct$
  Set rg1 = [b2:g10]: Set rg2 = [e6:i14]
  rg1.Interior.Color = #00ffff: rg2.Interior.Color = #ffff00
  intrsct = Intersect(rg1, rg2).Address(0, 0): Stop
  Range(BaseModOut(rg1.Address(0, 0), intrsct)).Interior.Color = 255
  Range(BaseModOut(rg2.Address(0, 0), intrsct)).Interior.Color = #0000ff
End Sub

Function BaseModOut(BaseAdr As String, OutAdr As String) As String
  Dim SU As Boolean, DA As Boolean, EE As Boolean, CM As Long
  With Application
    SU = .ScreenUpdating: .ScreenUpdating = False: CM = .Calculation
    .Calculation = xlCalculationManual: DA = .DisplayAlerts: .DisplayAlerts = False
    EE = .EnableEvents: .EnableEvents = False:  Worksheets.Add: Range(OutAdr) = 1
    Cells(Rows.Count, .Columns.Count) = 1: If WorksheetFunction.CountBlank(Range(BaseAdr)) > 0 _
    Then BaseModOut = Range(BaseAdr).SpecialCells(xlCellTypeBlanks).Address
    ActiveSheet.Delete: .ScreenUpdating = SU: .DisplayAlerts = DA: .EnableEvents = EE: .Calculation = CM
  End With
End Function
и чуть позже Jack Famous, прочтет всем лекцию в каких ситуациях это не сработает и как это сделать на 16 миллисекунд быстрее (если местами заменить Long на Boolean)
Программисты - это люди, решающие проблемы, о существовании которых Вы не подозревали, методами, которых Вы не понимаете!
 
… и как перестать бояться кнопки Enter  :D

PooHkrd, а прикольно!  :D  :idea:
Изменено: Jack Famous - 14.10.2021 13:58:53
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Код
Function NONOVERLAPPING(R1 As Range, R2 As Range) As Range
Application.ScreenUpdating = False
For Each CELL In Union(R1, R2)
If Intersect(CELL, R1, R2) Is Nothing Then
CELL.AddComment
End If
Next
Set NONOVERLAPPING = Union(R1, R2).SpecialCells(xlCellTypeComments)
NONOVERLAPPING.ClearComments
Application.ScreenUpdating = True
End Function

Код
Function NONOVERLAPPING1(R1 As Range, R2 As Range) As Range
Application.ScreenUpdating = False
Union(R1, R2).FormatConditions.Add xlExpression, , "=1"
Intersect(R1, R2).FormatConditions.Delete
Set NONOVERLAPPING1 = Union(R1, R2).SpecialCells(xlCellTypeAllFormatConditions)
NONOVERLAPPING1.FormatConditions.Delete
Application.ScreenUpdating = True
End Function
Изменено: БМВ - 14.10.2021 23:17:29
По вопросам из тем форума, личку не читаю.
 
Вот так еще можно попробовать
все уже изобрели :)
Изменено: Дмитрий(The_Prist) Щербаков - 15.10.2021 09:19:45
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
Дмитрий(The_Prist) Щербаков,  так цеж вариант 2  из предыдущего поста.
всех этих вариантов есть один минус, это то что они коверкают что-то на листе если не делать это на временном.
Изменено: БМВ - 15.10.2021 11:58:59
По вопросам из тем форума, личку не читаю.
 
Цитата
БМВ написал:
это то что они коверкают что-то на листе если не делать это на временном
ну, у меня подход был чуть иной - там только последнее наложенное форматирование удалялось:
Код
Sub Test()
    Dim x As Range, y As Range
    Dim rr As Range
    Set x = Range("B3:D6")
    Set y = Range("C5:F7")
    Union(x, y).FormatConditions.Add xlExpression, xlAnd, "=""xy"""
    Set rr = Intersect(x, y)
    rr.FormatConditions(rr.FormatConditions.Count).Delete
    Set rr = Union(x, y).SpecialCells(xlCellTypeAllFormatConditions)
    MsgBox rr.Address
    Union(x, y).FormatConditions(Union(x, y).FormatConditions.Count).Delete
End Sub
так что технически - после выяснения пересечения, все должно вернуться на исходную позицию.
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
Цитата
БМВ написал:
Intersect(R1, R2).FormatConditions.Delete
Ну, или так. Михаил, Дмитрий, Спасибо за реализацию безумных идей. Интересно.
Осталось дождаться Алексея, вдруг ему вштырит погонять миллисекунды.
Кстати, у УФ какое ограничение на длину адресной строки?
Вот горшок пустой, он предмет простой...
 
Цитата
PooHkrd написал:
у УФ какое ограничение на длину адресной строки?
не совсем понял вопрос. Если речь про условие в УФ - то через VBA 256 символов. А если про диапазон, к которому применяем УФ - то тут ограничения больше связаны с ограничениями к формированию диапазона, а не к УФ. Т.е. все ограничения, которые применяются к Union по сути.
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
Цитата
PooHkrd: Осталось дождаться Алексея, вдруг ему вштырит погонять миллисекунды
пока не очень интересно и обычно мои решения всё-таки дают более ощутимый (часто - кратный) прирост, нежели "миллисекунды". Про них [миллисекунды] совсем недавно один очень завистливый дедушка сболтнул просто из чувства зависти - фу таким быть :)

По вопросу я всё написал: любые решения на основе Union (тем более без его оптимизации) будут медленными, что, однако, не значит, что они плохие - в зависимости от объёма, выигрыша можно не почувствовать, а размер и сложность кода вырастят в разы
Если Бахтиёру надо будет быстро, то он спросит, но мне кажется, что он просто спрашивал про встроенный инструмент, обратный Intersect
Изменено: Jack Famous - 15.10.2021 10:25:50
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Спасибо всем. Сохранил в избранное, при необходимости буду пользоваться.
Цитата
Jack Famous:  просто спрашивал про встроенный инструмент, обратный Intersect'у
Это близко к истине.
Думаю тема получилась полезная для тех, кто поиском найдёт её.
Изменено: Бахтиёр - 15.10.2021 10:20:27
 
Цитата
Jack Famous написал:
любые решения на основе Union (тем более без его оптимизации) будут медленными
ну здесь всего два не рваных диапазона, так что тормозов быть явно не должно. Union хорошо начинает тормозить при более значительном кол-ве добавленных диапазонов.
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
Дмитрий(The_Prist) Щербаков, так я ж и написал
Цитата
Jack Famous: в зависимости от объёма, выигрыша можно не почувствовать
— мы же понимаем, что пример может (но не обязан  :D ) сильно отличаться по объёму от реальной задачи
Как говорится, предупреждён — значит вооружён. Лишним не будет, а не надо — забудет  :D

Может оттого я стараюсь все нюансы ТСам объяснять, что МНЕ в своё время с этим мало помогали (но помогали и ты - в том числе  :idea: ) и много шишек набить пришлось, пока своим умом и долгими тестами допёр…
О важности нюансов
Изменено: Jack Famous - 15.10.2021 12:07:11
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Если УФ просто подкрасить, то нужны ячейки с диапазонами или в формуле диапазоны задавать. Формула массива:
Код
=ИЛИ(СТРОКА(ДВССЫЛ($G$1))+СТОЛБЕЦ(ДВССЫЛ($G$1))%=СТРОКА(A1)+СТОЛБЕЦ(A1)%)+ИЛИ(СТРОКА(ДВССЫЛ($G$2))+СТОЛБЕЦ(ДВССЫЛ($G$2))%=СТРОКА(A1)+СТОЛБЕЦ(A1)%)=1
 
Светлый,
тоже самое но короче
=AND(OR(ISREF(B3 INDIRECT($G$1));ISREF(B3 INDIRECT($G$2))); NOT(ISREF(B3 INDIRECT($G$1) INDIRECT($G$2))))
правда придется в имена положить формулу
Изменено: БМВ - 15.10.2021 12:49:12
По вопросам из тем форума, личку не читаю.
 
Цитата
PooHkrd написал:
Михаил, Дмитрий, Спасибо за реализацию безумных идей
я так понял Function BaseModOut(BaseAdr As String, OutAdr As String) As String
работает только у меня и больше нигде...
Программисты - это люди, решающие проблемы, о существовании которых Вы не подозревали, методами, которых Вы не понимаете!
 
Цитата
БМВ написал:
тоже самое но короче
Формула на основе пересечения диапазонов у меня ещё короче, но УФ не разрешает их использовать.
*Такая формула:
Код
=ЕОШ(ДВССЫЛ($G$1) B3)+ЕОШ(ДВССЫЛ($G$2) B3)=1
Изменено: Светлый - 16.10.2021 16:48:41
 
Цитата
Дмитрий(The_Prist) Щербаков написал:
так что технически - после выяснения пересечения, все должно вернуться на исходную позицию.
Согласен, я не учел что не могут два пересекающихся диапазона иметь разное количество CF, но если в указанных диапазонах будут диапазоны со своими СF, то будет сбой.

Светлый, по этому я и указываю
Цитата
БМВ написал:
правда придется в имена положить формулу
По вопросам из тем форума, личку не читаю.
 
Цитата
БМВ написал:
но если в указанных диапазонах будут диапазоны со своими СF, то будет сбой
не думаю. Мы добавляем свое условие, которое автоматом будет иметь последний индекс. И потом по кол-ву этих самых УФ мы самый последний и удаляем - т.е. наш добавленный. Какие могут быть сбои?
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
Цитата
Дмитрий(The_Prist) Щербаков написал:
Мы добавляем свое условие, которое автоматом будет иметь последний индекс.
но ведь там будет именно число, а не LAST  и если у части одного диапазона был исходно один CF а у другой части 2 то  белиберда получается, сперва при добавлении, а после при удалении.
По вопросам из тем форума, личку не читаю.
Страницы: 1
Наверх