Каков наиболее эффективный способ получения «разницы в наборах» в Excel Automation? - PullRequest
0 голосов
/ 28 февраля 2009

Дана пара диапазонов, где известно, что один содержит элементы другого:

src = ActiveSheet.UsedRange
sel = src.SpecialCells(xlCellTypeVisible)

Какой самый эффективный способ получить новый диапазон, который представляет собой разность наборов между этими двумя диапазонами, то есть ячейками в src, которые не в sel?

Это можно сделать с помощью цикла над ячейками в src, но для этого требуется m * n Автоматизированные вызовы для диапазона m на n, который не имеет очень хорошей производительности, и я надеюсь, за то, что требует меньше удаленных вызовов API.

Ответы [ 4 ]

4 голосов
/ 02 марта 2009

Вы пытались использовать встроенные формулы Excel для фильтрации данных? Например, следующая формула выведет «Да», если значение в ячейке A2 находится в столбце D. В вашем случае вы можете просто получить все ячейки, для которых нет соответствующего «Да».

=IF(MATCH(A2,D:D, 0)>0,"Yes","No")
2 голосов
/ 07 июня 2013

Чтобы расширить ответ Тома Э, у меня возникает одна проблема: * когда нет совпадения, =MATCH() возвращает #N/A, что не нравится всей функции.

Чтобы исправить эту проблему, вы можете сделать следующее изменение в уравнении:

=IF(ISNA(MATCH(A2,D:D, 0)),"No","Yes")

ISNA() эффективно преобразует число в Yes, а #N/A (без совпадений) в No, что мы и хотим. Обратите внимание, что я должен был изменить порядок Да и Нет из-за того, как ISNA() функционирует.

2 голосов
/ 02 марта 2009

Я не думаю, что есть лучший способ, чем перебирать каждую ячейку в src. Объект Excel.Application имеет функцию Intersect, которая сообщает, какие ячейки содержатся в двух или более диапазонах, но не наоборот. Вы также можете выполнить объединение, которое просто даст вам диапазон со всеми ячейками в двух или более диапазонах ...

Но я думаю, что вам придется пройти через каждую клетку в src и посмотреть, есть ли в ней ...

Function GetInvisibleCells() As Range
    Dim src As Range, sel As Range

    Set src = ActiveSheet.UsedRange
    Set sel = src.SpecialCells(xlCellTypeVisible)

    Dim Isection As Range
    Set Isection = Application.Intersect(src, sel)

    Dim Result As Range

    Dim cl As Range
    For Each cl In src ' Go find all the cells in range2 that aren't in Isection
        If Application.Intersect(cl, Isection) Is Nothing Then
            ' Cl is not in sel
            If Not Result Is Nothing Then
                Set Result = Range(Result, cl)
            Else
                Set Result = cl
            End If
            ' Debug.Print Cl.Address & " is in " & src.Address & " and not in " & sel.Address
        End If
    Next cl
    Application.Intersect
    Set GetInvisibleCells = Result

End Function

Есть несколько подробных подходов здесь

0 голосов
/ 08 июня 2013

Вот еще один способ сделать это. Согласно методу ColumnDifferences из MSDN : « Возвращает объект Range, представляющий все ячейки, содержимое которых отличается от ячейки сравнения в каждом столбце ».

Исходя из этого, я применил следующую стратегию:

(1) Сохранить содержимое src в Variant.

(2) Заменить содержимое sel чем-то совершенно случайным.

(3) Используйте метод ColumnDifferences для получения желаемого диапазона.

(4) Возвращать исходные значения src, которые хранятся в Variant.

Реализация вышеперечисленных шагов следующая:

Dim src As Range, sel As Range, rngDiff As Range, varTempStorage As Variant
Dim icnt1 As Long, icnt2 As Long

Set src = ActiveSheet.UsedRange
Set sel = src.SpecialCells(xlCellTypeVisible)

' Store the src values in a variant
varTempStorage = src.Value

' Fill up the visible range with something random
sel.Value = "something completely random"

' Will return an error if nothing is found so needs appropriate error handling
' If it works, it should set rngDiff to point to the hidden cells only
Set rngDiff = src.ColumnDifferences(Comparison:=src(1,1))

' Pass data from variant to range - method taken from CPearson's website
Set src = src(1, 1)
src.Resize(UBound(varTempStorage, 1), UBound(varTempStorage, 2)).Value = varTempStorage

' Have a look at the output
For icnt1 = 1 To rngDiff.Rows.Count
    For icnt2 = 1 To rngDiff.Columns.Count
        Debug.Print " address: "; rngDiff(icnt1, icnt2).Address; " value: "; rngDiff(icnt1, icnt2)
    Next icnt2
Next icnt1

Метод RowDifferences должен давать одинаковые результаты - это потому, что мы заменяем все ячейки в видимом диапазоне, чтобы оба метода вели себя одинаково.

Я проверил вышесказанное, сгенерировав случайные числа в строках 1 - 17 и столбцах A - U, и скрыв строки 7 - 10, и он выполнил свою работу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...