Выделить цветом дубликаты значений во всех листах книги
Есть макрос для выделения и подсветки дубликатов в выделенном диапазоне ячеек Excel.
Мне нужно, чтобы он выделял дубликаты во всей книге, даже если они на разных листах. Т.е. чтобы массивом был не выделенный диапазон, а все заполненные ячейки на всех листах. Вот сам макрос:
Sub ColorsDoubles()
On Error Resume Next
' массив цветов, используемых для заливки ячеек-дубликатов
Colors = Array(12900829, 15849925, 14408946, 14610923, 15986394, 14281213, 14277081, _
9944516, 14994616, 12040422, 12379352, 15921906, 14336204, 15261367, 14281213)
Dim coll As New Collection, dupes As New Collection, _
cols As New Collection, ra As Range, cell As Range, n&
Err.Clear: Set ra = Intersect(Selection, ActiveSheet.UsedRange)
If Err Then Exit Sub
ra.Interior.ColorIndex = xlColorIndexNone: Application.ScreenUpdating = False
For Each cell In ra.Cells ' запонимаем значение дубликатов в коллекции dupes
Err.Clear: If Len(Trim(cell)) Then coll.Add CStr(cell.Value), CStr(cell.Value)
If Err Then dupes.Add CStr(cell.Value), CStr(cell.Value)
Next cell
For i& = 1 To dupes.Count ' заполняем коллекцию cols цветами для разных дубликатов
n = n Mod (UBound(Colors) + 1): cols.Add Colors(n), dupes(i): n = n + 1
Next
For Each cell In ra.Cells ' окрашиваем ячейки, если для её значения назначен цвет
cell.Interior.Color = cols(CStr(cell.Value)) ' если надо окрасить всю строку,то cell.EntireRow.Interior.color = cols(CStr(cell.Value))
Next cell
Application.ScreenUpdating = True
End Sub
По комментарию ниже сделал - не получилось.
Sub ColorsDoubles()
On Error Resume Next
' массив цветов, используемых для заливки ячеек-дубликатов
Colors = Array(12900829, 15849925, 14408946, 14610923, 15986394, 14281213, 14277081, _
9944516, 14994616, 12040422, 12379352, 15921906, 14336204, 15261367, 14281213)
Dim coll As New Collection, dupes As New Collection, _
cols As New Collection, ra As Range, cell As Range, n&
For Each oneSheet In ThisWorkbook.Sheets
Err.Clear: Set ra = oneSheet.UsedRange
Next
If Err Then Exit Sub
ra.Interior.ColorIndex = xlColorIndexNone: Application.ScreenUpdating = False
For Each cell In ra.Cells ' запонимаем значение дубликатов в коллекции dupes
Err.Clear: If Len(Trim(cell)) Then coll.Add CStr(cell.Value), CStr(cell.Value)
If Err Then dupes.Add CStr(cell.Value), CStr(cell.Value)
Next cell
For i& = 1 To dupes.Count ' заполняем коллекцию cols цветами для разных дубликатов
n = n Mod (UBound(Colors) + 1): cols.Add Colors(n), dupes(i): n = n + 1
Next
For Each cell In ra.Cells ' окрашиваем ячейки, если для её значения назначен цвет
cell.Interior.Color = cols(CStr(cell.Value)) ' если надо окрасить всю строку,то cell.EntireRow.Interior.color = cols(CStr(cell.Value))
Next cell
Application.ScreenUpdating = True
End Sub
Все окрасило одним цветом. Применяю в этом файле: https://yadi.sk/d/XbjB8sE9f8qkBQ.
В нем надо выделить те артикулы, которые повторяются на других листах. Файл с кодом: https://yadi.sk/i/vt7kK9hJN7e5Pg
Я что-то делаю не так?
Ответы (2 шт):
В цикле каждый из листов книги выбираем как лист-образец, сверяем его значения со значениями всех листов (включая лист-образец)...
Без оптимизации. Листы-образцы не исключаются из дальнейшей проверки и заливка ячеек может повторяться по несколько раз. На результат не влияет, но - дополнительное время на обработку.
Sub ColorsDoubles()
Dim sht1 As Worksheet, sht2 As Worksheet
Dim rRng1 As Range, rRng2 As Range, c1 As Range, c2 As Range
Dim lColor As Long
lColor = RGB(250, 150, 150)
Application.ScreenUpdating = False
For Each sht1 In Worksheets
Set rRng1 = sht1.UsedRange
For Each sht2 In Worksheets
Set rRng2 = sht2.UsedRange
For Each c1 In rRng1
If c1.Value <> "" Then
For Each c2 In rRng2
If c1.Address <> c2.Address Then
If c1.Value = c2.Value Then c2.Interior.Color = lColor
End If
Next c2
End If
Next c1
Next sht2
Next sht1
Set rRng1 = Nothing: Set rRng2 = Nothing
Application.ScreenUpdating = True
End Sub
Как вариант ускорения: создать массив с именами листов.
В примере красным закрашиваются ячейки, у которых есть дубли или на этом же листе, или на следующих. Зеленые - последние дублированные значения.
Sub ColorsDoubles()
Dim sht As Worksheet
Dim aNameSheets()
Dim rRng1 As Range, rRng2 As Range, c1 As Range, c2 As Range
Dim lCountSheets As Long, lColor1 As Long, lColor2 As Long
Dim i As Long, n As Long
lCountSheets = ThisWorkbook.Sheets.Count
ReDim aNameSheets(1 To lCountSheets)
For Each sht In Worksheets
n = n + 1
With sht
aNameSheets(n) = .Name 'имя листа в массив'
.UsedRange.Interior.Pattern = xlNone 'удаление заливки на листе'
End With
Next sht
lColor1 = RGB(200, 150, 150) 'цвета'
lColor2 = RGB(150, 200, 150)
Application.ScreenUpdating = False
For i = 1 To lCountSheets
Set rRng1 = Worksheets(aNameSheets(i)).UsedRange 'диапазон листа-образца'
For n = i To lCountSheets
Set rRng2 = Worksheets(aNameSheets(n)).UsedRange 'диапазоны следующих листов'
For Each c1 In rRng1
If c1.Value <> "" Then 'если значение в ячейке-образце есть'
For Each c2 In rRng2
If i = n And c1.Address = c2.Address Then
Else 'если сравнивается не сама с собой'
If c1.Value = c2.Value Then 'если значения совпали'
c1.Interior.Color = lColor1 'красим'
c2.Interior.Color = lColor2
End If
End If
Next c2
End If
Next c1
Next n
Next i
Set rRng1 = Nothing: Set rRng2 = Nothing 'освобождаем память'
Application.ScreenUpdating = True
End Sub
Мою проблему мне помогли решить тут
Вот решение, пусть и не совсем такое, как изначально предполагалось. Данный макрос ищет дубликаты в столбце с заданным именем и выводит список значений с указанием их местоположений.
Sub UniqArticul()
Dim Sht As Worksheet
Dim i As Long
Dim iLastRow As Long
Dim FoundCell As Range
Dim ColArticul As Integer
Dim dict As Object
Dim arr
Dim Col As String
Col = Application.InputBox("Укажите название столбца", , , , , , , 2)
ThisWorkbook.Sheets.Add.Name = "Дубликаты"
Set dict = CreateObject("Scripting.Dictionary"): dict.comparemode = 1
For Each Sht In Worksheets
If Sht.Name <> "Дубликаты" Then
With Sht
Set FoundCell = .Rows(1).Find(Col, , xlValues, xlWhole)
If Not FoundCell Is Nothing Then
ColArticul = FoundCell.Column
iLastRow = .Cells(.Rows.Count, ColArticul).End(xlUp).Row
arr = .Range(.Cells(2, ColArticul), .Cells(iLastRow, ColArticul))
For i = 1 To UBound(arr)
dict.Item(arr(i, 1)) = dict.Item(arr(i, 1)) + Sht.Name & " строка: " & i + 1 & "; "
Next
End If
Set FoundCell = Nothing
End With
End If
Next
Columns("C:D").ClearContents
Range("C1").Resize(dict.Count, 2) = Application.Transpose(Array(dict.keys, dict.Items))
End Sub