2015-05-31 3 views
-3

Я хотел бы выделить повторяющиеся строки в Excel VBA. Предположим, у меня есть следующий пример таблицы со столбцами A, B, C и D для тестирования:Выделение повторяющихся строк

A  B  C  D (Strings) 

1  1  1  dsf 
2  3  5  dgdgdgdg 
1  1  1  dsf 
2  2  2  xxx 
6  3  4  adsdadad 
2  2  2  xxx 

повторяющиеся строки должны быть выделены в любой цвет, например серый. Я смотрю идеально для быстрого выполнения кода, так как он будет использоваться для довольно больших таблиц. Примечание. Существуют решения для выделения повторяющихся ячеек (но не дубликатов строк). Я не знаю, как определить, являются ли строки дублирующими и в то же время, как это сделать быстро, то есть без вложенного цикла. Решение должно быть в VBA (не Excel).

Каков наилучший/самый быстрый способ достичь этого?

+0

насчет сортировки, а затем вам нужно только один цикл, который проверяет если одна строка как строка раньше? – pony2deer

+0

@ pony2deer Я не знаю, если это имеет значение, потому что вам все равно придется перебирать всю таблицу для каждой отдельной строки, даже если она отсортирована – EDC

+0

, даже встроенная функция должна зацикливаться хотя бы один раз по всей таблице , вы не можете сравнивать значения без «касания» их по крайней мере один раз – pony2deer

ответ

2

я испытал 3 различных подходов к файлу образца link от комментария OP в. Вероятно реализации VBA не были оптимальными, но ниже приведены результаты со средним временем 100 проходов:

1) Условное форматирование с использованием:

а) SUMPRODUCT конкатенация колонны - 3s

б) COUNTIFS с полным ссылка на столбец - 1.9s

с) COUNTIFS ссылок используются диапазоны - 0.2s

2) сортировка диапазона по всем столбцам, сравнивающие строки по ро ж, сортировка назад - 0.3с

3) Используя расширенный фильтр 3.5с

Вот код для самого быстрого способа:

Sub CF1() 

    Application.ScreenUpdating = False 

    Dim sFormula As String 
    Dim rRng As Range 
    Dim nCol As Integer, i As Integer 

    Set rRng = Range("A1").CurrentRegion 
    nCol = rRng.Columns.Count 

    'build the formula 
    sFormula = "=COUNTIFS(" 

    For i = 1 To nCol 
     sFormula = sFormula & rRng.Columns(i).Address & "," & _ 
     rRng.Cells(1, i).Address(False, True) 
     If i < nCol Then sFormula = sFormula & "," 
    Next 
    sFormula = sFormula & ")>1" 

    'write the formula in helper cell to get it's local version 
    rRng.Cells(1, nCol + 1).Formula = sFormula 

    rRng.FormatConditions.Delete 
    With rRng.FormatConditions.Add(Type:=xlExpression, _ 
      Formula1:=rRng.Cells(1, nCol + 1).FormulaLocal) 
     .Interior.ThemeColor = xlThemeColorAccent3 
    End With 

    rRng.Cells(1, nCol + 1).Clear 

    Application.ScreenUpdating = True 
End Sub 
+0

спасибо за ваше время и силы! Великий зол. Не могли бы вы также указать код для расширенных фильтров? – EDC

+1

сладкий материал!вы также можете опубликовать свой тестовый код, меня интересует подход VBA к использованию словаря и тестирование существующих ключей (хотя объект словаря будет вызван через COM, так что это может быть и на самом деле медленным) –

+0

@ VincentDeSmet код _benchmark_ было довольно просто - API API GetTickCount' до и после запуска цикла из 100 вызовов каждого Sub. Я не уверен, что это лучший подход, но я думаю, этого было достаточно, чтобы получить общее сравнение скорости. – BrakNicku

4

добавить условное форматирование с помощью следующей формулы SUMPRODUCT (или COUNTIFS)

=SUMPRODUCT(($A$1:$A$6&$B$1:$B$6&$C$1:$C$6=$A1&$B1&$C1)*1)>1

conditional formatting

Пояснение:

SUMPRODUCT удобно работать с диапазонами, которые вам нужны для управления до проверки состояния. В этом случае я объединяю A, B & C столбцов в диапазоне и сравниваю их с конкатенацией текущей строки. Затем я преобразовываю массив TRUE/FALSE в массив 1/0 путем умножения на 1, а часть SUMSUMPRODUCT суммирует строки, где условие истинно, и дает мне повторяющиеся строки (все вхождения). Если у вас небольшой диапазон, используя оценку формулы, вы можете четко видеть, как это работает.

Это быстрое решение, но производительность не идеальна, я использую ее для обнаружения дубликатов или создания последовательных номеров.

Решение от комментариев, предложенных ponydeer - более высокая производительность

на основе сортировки предполагая, требует, чтобы добавить ключевой столбец, положить в авто фильтры и сортировки по ключу, а затем сделать обусловливающие ключевого столбца:

Sorted

+0

не уверен, почему проголосовали за отказ, решение работает, хотя это может быть не самая лучшая производительность для большого рабочего листа (выключите автоматическое вычисление во время работы над листом и используйте 'SHIFT' +' F9' для обновления) –

+2

++ для решения. Возможно, я использовал более эффективную функцию [COUNTIFS] (https://support.office.com/en-us/article/COUNTIFS-function-53C4DC8E-0E5B-4E32-93DF-9CA5E7DA89ED); возможно, в именованном диапазоне, определяющем .CurrentRegion. – Jeeped

+1

спасибо за кредит =) – pony2deer

3

Сортируйте диапазон первых относительно всех столбцов

Workbooks(1).Sheets(1).Range("A:C").Sort Key1:=Workbooks(1).Sheets(1).Range("A:A"), Order1:=xlAscending, Key2:=Workbooks(1).Sheets(1).Range("B:B"), Order2:=xlAscending, Key3:=Workbooks(1).Sheets(1).Range("C:C"), Order3:=xlAscending, Orientation:=xlSortRows 

Затем цикл по всем строкам го сравнить их с тем, над ними

Dim a As Application 
Set a = Application 

For i=1 to 1000 ' here you need to set the number of rows you have 
    if Join(a.Transpose(a.Transpose(ActiveSheet.Rows(i).Value)), Chr(0)) = _ 
    Join(a.Transpose(a.Transpose(Sheets(1).Rows(i+1).Value)), Chr(0)) then 

     Sheets(1).Range(i+1 & ":" & i+1).EntireRow.Interior.Color = 49407 

    end if 

Next i 

Сравнение двух строк на основе этой теме: How to compare two entire rows in a sheet

Пожалуйста вставьте имена вашей рабочей книги, листа и установить диапазон и пределы в коде сам.

+0

Спасибо, я попробую! – EDC

+0

Одна вещь, которую я только что заметил: могу ли я снова отменить сортировку? Я хотел бы сохранить исходный порядок, потому что он содержит информацию о времени (верхние строки были созданы ранее и т. Д.). – EDC

+0

возможно последнее сообщение этой темы, это то, что вы ищете http://windowssecrets.com/forums/showthread.php/8265-UNDO-AN-ACTION-IN-VBA – pony2deer

2

Я думаю, что самый быстрый/лучший будет зависеть от доли дубликатов - только одна строка должна быть быстрее 50%, как в примере, - и от фактического размера массива (сколько столбцов, из которых можно создать ключ, и т.д).

Учитывая, что редко можно бить встроенные функции с помощью «чистого» VBA, я подозреваю, что с помощью пользовательского интерфейса, в случае необходимости, VBA будет быстрее в некоторых случаях.Например:

Добавить столбец с индексом (заполнить серийный номер), скопировать весь лист (скажем в Sheet2), применить Удалить дубликаты для всех, кроме столбца индекса, а затем применить в качестве правила формулы CF такого типа соответствующий диапазон оригинала лист:

=$A1=MATCH($A1,Sheet2!$A$1:$A$3000,0)>0 

Предполагая, что начальная точка находится примерно так:

SO30558893 first example

и Columna вставляется с цифровой заливки серии начиная 1, Лист2 должен выглядеть так после Удалить Дубликаты:

SO30558893 second example

я предположил, что ColumnE будет проигнорирована, насколько тиражирование обеспокоен.

В исходном листе выберите массив (от A1: - see!), Например A1: I6 и HOME> Стили - Условное форматирование, Новое правило ..., Используйте формулу, чтобы определить, какие клетки форматировать, Формат значения, где эта формула верна::

=$A1=MATCH($A1,Sheet2!$A:$A,0)>0 

Формат ..., заполняющая, серый, OK, OK.

Для меня приводит:

SO30558893 third example

+0

звучит интересно, но я не знаю что вы подразумеваете под этим: «применять в качестве правила CF-формулы такого типа соответствующий диапазон исходного листа:' = $ A1 = MATCH ($ A1, Sheet2! $ A $ 1: $ A $ 3000,0)> 0' '. После того, как я удалю дубликаты, я бы сделал это или нет? – EDC

+1

Я думаю, что в этом подходе CF выделит только одну из двух одинаковых строк (или n-1 из n) – BrakNicku

+0

@ user3964075 Правда, и очень хорошая точка. Но использование кажется неоднозначным - например, функция Remove Duplicates в Excel оставляет одну из пары. * One * [определение] (http://www.oxforddictionaries.com/definition/english/duplicate) - это «Копия оригинала:», поэтому с двумя экземплярами может быть «оригинал» *, а не «дубликат». – pnuts

Смежные вопросы