Замена первого дубликата последним в строке первого дубликата - Excel VBA - PullRequest
0 голосов
/ 18 февраля 2019

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

Я хочу удалить дубликаты на основе идентификационного номера, сохранив последние записи от столбца A до C. Кроме того, я хочу сохранить каждую ячейку в столбце Dи столбец E из первых записей.В конечном итоге это означает, что самые последние записи будут заменены в столбцах A, B и C первых записей.

Важное примечание: столбец D & E будет заполняться только в первой записи каждого идентификатора.Все дополнительные строки с одним и тем же идентификатором всегда будут содержать пустые ячейки в столбцах D & E.

Для большей ясности см. Таблицы ниже, в которых отражены объяснения выше: Example with the first table: database, second table: result after macro

На основании приведенного выше примера это означает:

  • Удаление дубликатов на основе идентификатора из столбцов от A до C и сохранение последних записей каждого идентификатора (от столбца A доC: Удалить содержимое в строках 1, 2, 3, 5 и 6 + сохранить последние записи каждого идентификатора (в данном случае это строки 4 и 7)

  • Сохранить столбцы D & E изпервые записи каждого идентификатора (обратите внимание, что только первые записи каждого идентификатора будут непустыми ячейками. В этом примере есть два идентификатора, 123 и 458, и только строки 1 и 2 из столбца D & E будут не-impty)

  • Заменить предыдущие записи самыми последними в строке предыдущих записей из столбца от A до C (от столбца A до C заменить строки 1 и 2 на строки 4 и 7соответственно)

Другими словами: обновить столбцы от A до Cбез изменения столбцов D в E

См. ниже те же таблицы с указанием: Two previous tables with indications

Я пробовал два разных кода, но оба не дают мне концаРезультаты, которые я ищу.

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

Sub Delete_Duplicates()
    Sheet5.Range("$A$1:$E$29999").RemoveDuplicates Columns:=Array(1) _
    , Header:=xlYes
End Sub  

Конечные результаты не точны, поскольку он сохраняет первые записи в столбцах от A до C: Table results after first macro test

Проблема в приведенном выше коде состоит в том, что он не меняет имя и дату на последние записи (которые будут соответственно Боб, 6-я неделя и Питер, 4-я неделя)

Следующий код, который я сделал, - сохранить самые новые записи, но это, к сожалению, удаляет мои записи в столбце D в E:

Sub Delete_Duplicates_2()
Dim Rng As Range, Dn As Range, n As Long
Dim Lst As Long, nRng As Range
Set Rng = Sheet5.Range("$A$2:$E$29999")
Lst = Range("A" & Rows.Count).End(xlUp).Row
    With CreateObject("scripting.dictionary")
    .CompareMode = vbTextCompare
    For n = Lst To 1 Step -1
    If Not .Exists(Range("A" & n).Value) Then
    .Add Range("A" & n).Value, Nothing
    Else
        If nRng Is Nothing Then
            Set nRng = Range("A" & n)
        Else
            Set nRng = Union(nRng, Range("A" & n))
        End If
    End If
    Next n
    If Not nRng Is Nothing Then 
    nRng.EntireRow.Delete
    End With
End Sub

Ниже приведен результат, который я получаю из второго кода: Table results after second macro test

Приведенный выше код отлично работает, чтобы заменить мои первые записи самыми последними, но он удаляет все в столбце D & E (Comments & Additional com).Мне было интересно, может быть, мой код можно изменить, только заменив дубликаты в определенных столбцах, вместо удаления всей строки (что, очевидно, является проблемой в этом коде).

Я надеюсь, что объяснения были достаточно ясны дляВы, чтобы помочь мне по этому вопросу.Пожалуйста, имейте в виду, что у меня есть тысячи строк, и индивидуальное решение для примера, который я привел, не будет тем, что я ищу.Я открыт для любых предложений и благодарю вас за помощь!

Ответы [ 2 ]

0 голосов
/ 18 февраля 2019

Эта подпрограмма использует объект словаря для удаления дубликатов.

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

Если у нас естьдубликат, мы проверяем, есть ли что-нибудь в столбцах 4 или 5, если есть, мы перезаписываем это в словаре (обратите внимание, что элемент (ы) массива не может быть изменен напрямую, но мы должны извлечь массив, изменить его,и поместите его обратно.

Затем мы создадим массив результатов и запишем его обратно на лист.

Разумный выбор wsRes, wsSrc и rRes позволит вам получитьрезультаты на отдельном рабочем листе или даже перезаписать исходные данные (хотя я бы не советовал это для целей аудита).

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

Option Explicit
'Set reference to Microsoft Scripting Runtime or
'    use late-binding
Sub deDup()
    Dim wsSrc As Worksheet, wsRes As Worksheet, rRes As Range
    Dim vSrc As Variant, vRes As Variant
    Dim vRow(2 To 5) As Variant, vKey As Variant, vTemp As Variant
    Dim I  As Long, J As Long
    Dim D As Dictionary

 Set wsSrc = Worksheets("sheet3")
 Set wsRes = Worksheets("Sheet3")
    Set rRes = wsRes.Cells(1, 9)

With wsSrc
    vSrc = .Range(.Cells(1, 1), .Cells(.Rows.Count, 1).End(xlUp)).Resize(columnsize:=5)
End With

Set D = New Dictionary
For I = UBound(vSrc, 1) To 2 Step -1
    vKey = vSrc(I, 1)
    If Not D.Exists(vKey) Then
        For J = 2 To 5
            vRow(J) = vSrc(I, J)
        Next J
        D.Add Key:=vKey, Item:=vRow
    Else
        If vSrc(I, 4) <> "" Or vSrc(I, 5) <> "" Then
            vTemp = D(vKey)
            vTemp(4) = vSrc(I, 4)
            vTemp(5) = vSrc(I, 5)
            D(vKey) = vTemp
        End If
    End If
Next I

ReDim vRes(0 To D.Count, 1 To 5)

    'Headers
    For J = 1 To 5
        vRes(0, J) = vSrc(1, J)
    Next J

    'Data
    I = 0
    For Each vKey In D.Keys
        I = I + 1
        vRes(I, 1) = vKey
        For J = 2 To 5
            vRes(I, J) = D(vKey)(J)
        Next J
    Next vKey

Set rRes = rRes.Resize(rowsize:=D.Count + 1, columnsize:=UBound(vRes, 2))
With rRes
    .EntireColumn.Clear
    .Value = vRes
    With .Rows(1)
        .Font.Bold = True
        .HorizontalAlignment = xlCenter
    End With
    .EntireColumn.AutoFit
End With
End Sub

enter image description here

0 голосов
/ 18 февраля 2019

У меня есть следующие данные (идентификатор столбца A, имя столбца B, данные столбца C)

A       B       C

1   a   Last

1   a   

2   b   pre

2   b   

3   c   test

3   c   test2

3   c   

3   c

Если вы получили уникальные идентификаторы и поместили их в столбец, используйте VBA или формулу дляthis.

Затем в VBA вы можете использовать evaluate, чтобы получить последнее значение из данных, например,

evaluate("INDEX($C$1:$C$8,MAX(($A$1:$A$8=F1)*($C$1:$C$8<>"""")*ROW($A$1:$A$8)),1)")

Где столбец F - этоуникальный идентификационный номер.

Предполагается, что данные расположены в хронологическом порядке.

...