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

У меня есть массив значений result, которые я получил из вызова REST API — result = [1,2,3,4,5], и они анализируются как варианты в функции AppendUnique.

Что я хочу сделать:

Функция AppendUnique добавляет уникальные значения из растущего массива result в диапазон в Excel. Я хочу добавить новую функцию в AppendUnique, где повторяющиеся значения в массиве result будут выделены в ячейке Excel.

Объяснение моего текущего кода:

В начале

Я ввожу каждое значение в массив result, чтобы заполнить ячейки от A1 до A5 (диапазон динамический, основанный на количестве значений в массиве, поэтому может не быть A5 все время).

Итак, если диапазон (A1-A100) пуст, мы заполняем ячейки как обычно.
^ эта часть завершена

По мере роста массива результатов

Поскольку результат будет увеличиваться при повторном запуске макроса, например, через 15 минут result может стать [1,2,3,4,5,6,7,8]

Итак, если диапазон (A1-A5) не пуст, мы добавляем дополнительные элементы массива в конец диапазона ячеек, если они не отображаются в диапазоне (то есть они являются дополнительными)
^ эта часть завершена

Результат также может содержать дубликаты, например, через 30 минут result может стать [1,2,3,4,5,6,7,8,3], где 3 — дубликат.

Если есть дубликат - 3, ячейка A3 (где мы заполнили 3) должна быть выделена.
^ этот вопрос об этой части

Мой текущий код:

Sub AppendUnique( _
        Arr() As Variant, _
        ByVal ws As Worksheet, _
        ByVal FirstCellAddress As String, _
        Optional ByVal OverWrite As Boolean = False)
   
    ' Write the data from the source range to the source array ('sData').
    ' Reference the first destination cell ('fCell').

    If ws.FilterMode Then ws.ShowAllData
    
    Dim fCell As Range: Set fCell = ws.Range(FirstCellAddress)
    
    Dim sData() As Variant, srCount As Long
    
    With fCell
        Dim lCell As Range: Set lCell = .Resize(ws.Rows.Count - .Row + 1) _
            .Find("*", , xlFormulas, , , xlPrevious)
        If Not lCell Is Nothing Then
            srCount = lCell.Row - .Row + 1
            If srCount = 1 Then
                ReDim sData(1 To 1, 1 To 1): sData(1, 1) = .Value
            Else
                sData = .Resize(srCount).Value
            End If
            If Not OverWrite Then Set fCell = lCell.Offset(1)
        End If
    End With
            
    ' Write the unique data from the source array to a dictionary.
    
    Dim dict As Object: Set dict = CreateObject("Scripting.Dictionary")
    dict.CompareMode = vbTextCompare
    
    Dim sr As Long
    
    For sr = 1 To srCount: dict(CStr(sData(sr, 1))) = Empty: Next sr
    
    Erase sData
    
    ' Define the destination array ('dData').
    
    Dim lb As Long: lb = LBound(Arr)
    Dim ub As Long: ub = UBound(Arr)
    
    Dim dData() As Variant: ReDim dData(1 To ub - lb + 1, 1 To 1)
                 
    ' Check the values from the given array ('Arr') against the values
    ' in the dictionary and write the non-matches to the destination array.
    
    Dim dr As Long, c As Long, cString As String
                 
    For c = lb To ub
        cString = CStr(Arr(c))
        If Len(cString) > 0 Then ' is not blank
            If Not dict.Exists(cString) Then ' is not in the dictionary
                dict(cString) = Empty ' prevent dupes from the given array
                dr = dr + 1
                dData(dr, 1) = cString
            End If
        End If
    Next c
    
    If dr = 0 Then
        MsgBox "No new values found.", vbExclamation
        Exit Sub
    End If
    
    ' Write the values from the destination array to the destination range.
    
    fCell.Resize(dr).Value = dData
    If OverWrite Then ' clear below
        fCell.Resize(ws.Rows.Count - fCell.Row - dr + 1).Offset(dr).Clear
    End If
        
    ' Inform.
        
    MsgBox "Data appended.", vbInformation
         
End Sub

Сначала я подумал, может быть, я могу сделать что-то под линией — If Len(cString) > 0 Then, чтобы добавить If dict. Exists(cstring) Then, выделить ячейку, выполнив что-то вроде interior.color = vbYellow.

Однако я понял, что в моем текущем коде продукты добавляются полностью после проверки повторяющихся элементов, поэтому я не совсем уверен, как выделить ячейку с повторяющимся значением, поскольку мы не зацикливаемся на добавленном диапазоне.

Любая помощь будет принята с благодарностью, заранее спасибо.

Не могли бы вы использовать условное форматирование?

SJR 10.01.2023 14:04

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

w97802 10.01.2023 14:29

Не думайте, что я понимаю. Что вы имеете в виду под автоматически? Вы не можете «подсветить» значения в массиве.

SJR 10.01.2023 17:09
Преобразование HTML-таблицы в профессиональный документ Excel
Преобразование HTML-таблицы в профессиональный документ Excel
Это самый простой способ создания Excel из HTML-таблицы.
Импорт excel в laravel в базу данных
Импорт excel в laravel в базу данных
Здравствуйте, дорогой читатель, в этой статье я расскажу практическим и быстрым способом, как импортировать файл Excel в вашу базу данных с помощью...
1
3
56
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Используйте значение словаря для хранения ссылки на соответствующую строку. Сложность заключается в том, чтобы различать существующие ключи из листа и добавленные из массива. Для режима Overwrite значения с листа устаревают. Я использовал конкатенированную строку смещения строки и либо ";sht", либо ";arr". Легко разделить 2 значения с помощью split(). Для выявления дубликатов в массиве я добавил еще один словарь — dupl.

Sub AppendUnique( _
        Arr() As Variant, _
        ByVal ws As Worksheet, _
        ByVal FirstCellAddress As String, _
        Optional ByVal OverWrite As Boolean = False)

    If ws.FilterMode Then ws.ShowAllData
    
    Dim fCell As Range, lCell As Range, tcell As Range
    Dim sData() As Variant, srCount As Long
     
    ' Write the data from the source range to the source array ('sData').
    ' Reference the first destination cell ('fCell').
    Set fCell = ws.Range(FirstCellAddress)
    If Len(fCell) = 0 Then
        srCount = 0
        ' target cell for appending new items
        Set tcell = fCell
        fCell.ClearFormats
    Else
        Set lCell = ws.Cells(ws.Rows.Count, fCell.Column).End(xlUp)
        srCount = lCell.Row - fCell.Row + 1
        If srCount > 1 Then
            sData = fCell.Resize(srCount).Value2
        Else
            ReDim sData(1 To 1, 1 To 1):
            sData(1, 1) = fCell.Value2
        End If
        ' clear any existing coloring
        fCell.Resize(srCount).ClearFormats
        
        ' target cell for appending new items
        Set tcell = lCell.Offset(1)
    End If
                
    ' Write the unique data from the source array to a dictionary.
    Dim dict As Object, sr As Long, r As Long
    Set dict = CreateObject("Scripting.Dictionary")
    dict.CompareMode = vbTextCompare
    
    r = 0 ' row offset
    If srCount > 0 Then
        For sr = 1 To UBound(sData)
            dict(CStr(sData(sr, 1))) = r & ";sht" ' fcell row offset +1
            r = r + 1
        Next sr
    End If
    
    ' reset target cell
    If OverWrite Then
        Set tcell = fCell
        r = 0
    End If
    
    ' Define the destination array ('dData').
    Dim lb As Long, ub As Long
    Dim dr As Long, c As Long, cString As String
    Dim dData() As Variant:
    lb = LBound(Arr)
    ub = UBound(Arr)
    ReDim dData(1 To ub - lb + 1, 1 To 1)
                 
    ' Check the values in Arr
    ' against the values in the dictionary and
    ' write the non-matches to the destination array.
    Dim dupl As Object, k
    Set dupl = CreateObject("Scripting.Dictionary")
    For c = lb To ub
        ' dictionary key
        k = CStr(Arr(c))
        If Len(k) > 0 Then ' is not blank
            If Not dict.Exists(k) Then
               ' is not in the dictionary
               ' prevent dupes from the given array
                dict(k) = r & ";arr ' store fcell offset"
                r = r + 1
                dr = dr + 1
                dData(dr, 1) = k
            End If
        
             ' check for duplicates in arr
            If dupl.Exists(k) Then
                dupl(k) = dupl(k) + 1
            Else
                dupl.Add k, 1
            End If
        End If
    Next c
    
     ' clear existing data
    If OverWrite And srCount > 0 And dr > 0 Then
        fCell.Resize(srCount).Clear
    End If
    
    ' Write the values from the destination array
    ' to the destination range.
    If dr > 0 Then
        tcell.Resize(dr).Value = dData
    End If
       
    ' highligh if duplicate
    Dim ar
    For Each k In dupl.keys
        If dupl(k) > 1 Then
            ar = Split(dict(k), ";")
            r = ar(0)
            If dr > 0 And OverWrite And ar(1) = "sht" Then
                ' do nothing as row information is useless
                ' for existing value with overwrite
            Else
                fCell.Offset(r).Interior.Color = RGB(255, 255, 0)
            End If
        End If
    Next
    
    If dr = 0 Then
        MsgBox "No new values found.", vbExclamation
    Else
        ' Inform.
        MsgBox dr & " Data rows appended.", vbInformation
    End If         
End Sub

Другие вопросы по теме