Нужен лучший оптимизированный код? - PullRequest
4 голосов
/ 30 августа 2011

Нужен сильно оптимизированный код. Хорошо, я получил проект и успешно справился с ним с помощью vba (в основном это помогало программистам stackoverflow, спасибо за это) Но сегодня я получил отзыв.Он удаляет еще 2 уникальные записи в записи, но я не знаю, почему он удаляет их.

Алгоритм, который я применил

Я использовал функцию COUNTIF, которую я нашел в Google

    ="countif(A$1:A2,A3)=0" A3 is the active cell, Checks A2,A1 for dupes

Он выдает «Ложь», если в столбце «А» есть дубликат, и «Истина», если он является уникальным. Что я понял о Каунтифе, так это то, что он проверяет все значения столбцов из этой ячейки, которые я имею в виду, давайте возьмем А4.ТАК это проверяет A2, A1, A3 для дубликата.Точно так же A10 проверяет A1 - A9 и выбрасывает либо TRue, либо False. Хорошо это работало, но я не знаю, что пошло не так. Код не работает для некоторых записей. Иногда он даже показывает False для уникальных записей.

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

Мне нужен код для этих условий, кто угоднопомогите мне, так как мой счетчик не удался. Я немного беспомощен в этом.

1) У меня есть столбец, и я должен проверить наличие дубликатов в этом столбце и удалить эту строку, если это дубликат

2) У меня есть 35000 старых записей в столбце, и у меня есть новые записи 2000 каждую неделю, они добавляются.Мне нужно проверить эти 2000 записей из общего числа 37000 (поскольку мы добавили, мы получаем 35000 + 2000), и эту операцию удаления необходимо выполнять только для вновь добавленных 2000 записей, но следует проверить дубликаты для всего столбца

Позвольте мне четко объяснить вам, что у меня есть 2000 новых записей, поэтому необходимо проверять только эти записи на наличие дубликатов из 35000 записей, а также от себя (2000 записей), и удалять его, если он является дубликатом, и операция дублирования не должна выполняться.выполнено на 35000 записей старых данных.

Я нашел несколько кодов, но они удаляют даже дубликаты 35000 записей.Я установил диапазон, но он не работает.Может ли кто-нибудь помочь мне с лучшим кодом, который занимает меньше времени? Пожалуйста, спасибо

Обновление моего вопроса с помощью примера кода, который у меня есть

   A       B            F       G        H       I              Y          
  PTY   39868.5         4       2       540      3      PTY39868.5425403 
  GTY   34446.1234      2       1       230      1      GTY34446.1234212301
  PTY   3945.678                2                2       PTY3945.67822
  GTY   34446.1234      2       1       230      1      GTY34446.1234212301
                  let us say these are old 35000 entries

Пояснение к приведенному выше примеру.

Выше 35000 записей.Я должен проверить столбцы A, B, F, G, H, I для дубликатов, если они совпадают, я должен удалить строку, я не должен беспокоиться о других столбцах c, d и т. Д., Поэтому я сделал этоиспользовал один неиспользуемый столбец Y и объединил эти значения 6 столбцов в 1 в столбце Y, используя эти

  = A2 & B2 & F2 & G2 & H2 &I2 with the respective columns

Теперь проверяя столбец Y на наличие дубликатов и удаляем всю строку.Насколько мне известно, 2003 поддерживает только один столбец.

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

   A       B            F       G        H       I              Y          
  PTY   39868.5         4       2       540      3      PTY39868.5425403     'old 
  GTY   34446.1234      2       1       230      1      GTY34446.1234212301   'old
  PTY   3945.678                2                2       PTY3945.67822        'old
  GTY   34446.1234      2       1       230      1      GTY34446.1234212301    'old
  PTY    3945.678       1       1       230      2      PTY3945.678112302      'new
  PTY    39868.5        4       2       540      3      PTY39868.5425403       'new 
  PTY    3945.678       1       1       230      2      PTY3945.678112302      'new

Теперь обратите внимание, что Новая запись PTY (из последних 2-х) является дубликатоморигинальной записи (вначале PTY) Так что я должен удалить ее. И последняя новая запись является дубликатом самой новой записи, поэтому я должен удалить ее даже это.Поэтому в приведенном выше коде я должен удалить только последние 2 строки, которые являются дубликатами исходной записи, а также из нее.Но не следует удалять GTY, который является обманом, но который находится в оригинальной записи.

Я думаю, что дал четкое представление сейчас.Объединяет их в одну клетку.Это лучший способ подойти?как конактенатин для 40000 записей, занимающих всего 2 секунды, я думаю, что это не имеет значения, но любые другие алгоритмы к ним очень ценятся

Я слышал, что значения 45,00 и 45,00000 различны, неужели это право, может быть, в этом была проблема?так как у меня есть десятичные точки в моих данных.Я думаю, что я должен сделать

    = I2 & H2 & G2 & F2 & A2 & B2

что лучше объединить? это или другой, который я отправил раньше?

Ответы [ 7 ]

5 голосов
/ 31 августа 2011

БОЛЬШОЕ ОБНОВЛЕНИЕ :

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

  • Если 35000 старых записей не содержат дубликатов, то все, что вам нужно сделать, это удалить все дубликаты из всего столбца - при условии, что вы начинаете со строки 1, вы не рискуете удалить любую из «старых» строк поскольку в них нет дубликатов.

Вот один из способов:

Sub UniqueList()

Application.ScreenUpdating = False
Dim vArray As Variant
Dim i As Long, j As Long, lastrow As Long
Dim dictionary As Object
Set dictionary = CreateObject("scripting.dictionary")

lastrow = Range("A" & Rows.Count).End(xlUp).Row
vArray = Range("A1:A" & lastrow).Value

On Error Resume Next
For i = 1 To UBound(vArray, 1)
    For j = 1 To UBound(vArray, 2)
        If Len(vArray(i, j)) <> 0 Then
            dictionary(vArray(i, j)) = 1
        End If
    Next
Next

Columns("A:A").ClearContents
Range("A1").Resize(dictionary.Count).Value = _
Application.Transpose(dictionary.keys)

Application.ScreenUpdating = True

End Sub
  • Если по какой-то странной причине 35000 старых записей действительно содержат дуплексы, и вы хотите, чтобы только эти 35000 записей делали это, то вы можете использовать 2 словаря, но это будет необычный случай, так как вы будете обращаться со старыми записи отличаются от новых ...
Sub RemoveNewDupes()

Application.ScreenUpdating = False
Dim lastRow As Long
Dim varray As Variant
Dim oldDict As Object, newDict As Object
Set oldDict = CreateObject("scripting.dictionary")
Set newDict = CreateObject("scripting.dictionary")

On Error Resume Next
lastRow = Range("A" & Rows.Count).End(xlUp).Row

'Add old entries to dictionary
varray = Range("A1:A35000").Value
For i = 1 To UBound(varray, 1)
    oldDict.Add varray(i, 1), 1
Next

'Check for dupes
varray = Range("A35001:A" & lastRow).Value
For i = 1 To UBound(varray, 1)
    If oldDict.exists(varray(i, 1)) = False Then
        newDict.Add varray(i, 1), 1
    End If
Next

'Delete and slap back on the unique list
Range("A35001", "A" & Rows.Count).ClearContents
Range("A35001").Resize(newDict.Count).Value = _
Application.Transpose(newDict.keys)

Application.ScreenUpdating = True
End Sub

Спасибо Reafidy за совет и заставил меня пересмотреть это.

5 голосов
/ 31 августа 2011

Это также ответ на некоторые комментарии и решения, сделанные другими участниками, поэтому извините, если он не сразу ответит на ваш вопрос.

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

При скоростном тестировании очень сложно получить ровное игровое поле в excel, так как на результаты влияют многие факторы. Спецификации компьютера, доступная оперативная память и т. Д. Код должен быть сначала скомпилирован перед выполнением любой из процедур. Тестовые данные также важны при рассмотрении дубликатов - сколько дубликатов и сколько строк. Эта подпрограмма загружает некоторые тестовые данные, и изменение количества строк в зависимости от диапазона случайных чисел (дубликатов) приведет к совсем другим результатам для вашего кода. Я не знаю, как выглядят ваши данные, поэтому мы работаем вслепую, и ваши результаты могут сильно отличаться.

'// This is still not very good test data, but should suffice for this situation.
Sub TestFill()
    '// 300000 rows
    For i = 1 To 300000
        '// This populates a random number between 1 & 10000 - adjust to suit
        Cells(i, "A").value = Int((100000 + 1) * Rnd + 1)
    Next
End Sub

Если мы говорим о расширенном фильтре по сравнению с массивом и диктонным методом, тогда расширенный фильтр будет быстрее с меньшим количеством строк, но как только вы достигнете определенного количества строк, метод массива будет быстрее. Тогда посмотрите, что произойдет, когда вы измените количество дубликатов .... :) В качестве руководства или общего правила использование встроенных функций excels будет быстрее, и я рекомендую всегда разрабатывать попытки использовать эти встроенные функции, однако часто бывают исключения, как выше при удалении дубликатов. :)

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

Sub RemoveDuplicatesA()

    '// Copy raw data to presentation sheet
    Range("A1", Cells(Rows.Count, "A").End(xlUp)).AdvancedFilter _
        Action:=xlFilterCopy, CopyToRange:=Sheet2.Range("B1"), Unique:=True

End Sub

Это будет самый быстрый метод:

Sub RemoveDuplicatesB()        
    Dim vData As Variant, vArray As Variant
    Dim lCnt As Long, lRow As Long

    vData = ActiveSheet.UsedRange.Columns(1).value
    ReDim vArray(0 To UBound(vData, 1), 0)
    lCnt = 0

    With CreateObject("Scripting.Dictionary")
        For lRow = 1 To UBound(vData, 1)
            If Not .Exists(vData(lRow, 1)) Then
                vArray(lCnt, 0) = vData(lRow, 1): lCnt = lCnt + 1
                .Add vData(lRow, 1), Nothing
            End If
        Next lRow
    End With

    '// Copy raw data to presentation sheet
    Sheet2.Range("B1").Resize(lCnt).value = vArray

End Sub

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

Sub RemoveDuplicatesC()
    Dim vData As Variant
    Dim lRow As Long

    vData = ActiveSheet.UsedRange.Columns(1).value

    With CreateObject("Scripting.Dictionary")
        For lRow = 1 To UBound(vData, 1)
            If Not .exists(vData(lRow, 1)) Then
                .Add vData(lRow, 1), Nothing
            End If
        Next lRow

        '// Copy raw data to presentation sheet or replace raw data
        Sheet2.Columns(2).ClearContents
        Sheet2.Columns(2).Resize(.Count).value = Application.Transpose(.keys)
    End With

End Sub 

EDIT

Хорошо, @Issun упомянул, что вы хотите удалить всю строку. Мое предложение состояло в том, чтобы улучшить макет вашей электронной таблицы, используя необработанные данные и презентационный лист, что означает, что вам не нужно ничего удалять, следовательно, это был бы самый быстрый метод. Если вы не хотите этого делать и хотите редактировать необработанные данные напрямую, попробуйте следующее:

 Sub RemoveDuplicatesD()
    Dim vData As Variant, vArray As Variant
    Dim lRow As Long       

    vData = ActiveSheet.UsedRange.Columns(1).value
    ReDim vArray(1 To UBound(vData, 1), 0)     

    With CreateObject("Scripting.Dictionary")
        For lRow = 1 To UBound(vData, 1)
            If Not .exists(vData(lRow, 1)) Then
                varray(lRow, 0) = "x"
                .Add vData(lRow, 1), Nothing
            End If
        Next lRow
    End With

    Application.ScreenUpdating = False

    '// Modify the raw data
    With ActiveSheet
        .Columns(2).Insert
        .Range("B1").Resize(lRow).value = vArray
        .Columns(2).SpecialCells(xlCellTypeBlanks).EntireRow.Delete
        .Columns(2).Delete
    End With

    Application.ScreenUpdating = True
End Sub
4 голосов
/ 30 августа 2011

ОК, вот метод расширенного фильтра.Не знаю, если это быстрее, чем метод словаря.Хотя было бы интересно узнать, так что дайте мне знать, когда вы попробуете.Я также включил часть удаления, так что вам придется остановить эту часть, если вы хотите сделать истинное сравнение.Кроме того, вы можете сделать это функцией вместо подпрограммы и поместить ее в свои переменные, однако вы хотите изменить ее.

Sub DeleteRepeats()

    Dim d1 As Double
    Dim r1 As Range, rKeepers As Range
    Dim wks As Worksheet


    d1 = Timer
    Set wks = ActiveSheet
    Application.EnableEvents = False
    Application.ScreenUpdating = False

    'Make sure all rows are visible
    On Error Resume Next
    wks.ShowAllData
    wks.UsedRange.Rows.Hidden = False
    wks.UsedRange.Columns.Hidden = False
    On Error GoTo 0

    'Get concerned range
    Set r1 = wks.Range("A1:A35000")
    'Filter
    r1.AdvancedFilter Action:=xlFilterInPlace, Unique:=True

    'Get range of cells not to be deleted
    Set rKeepers = r1.SpecialCells(xlCellTypeVisible)
    On Error Resume Next
    wks.ShowAllData
    On Error GoTo 0
    rKeepers.EntireRow.Hidden = True

    'Delete all undesirables
    r1.SpecialCells(xlCellTypeVisible).EntireRow.Delete

    'show all rows
    On Error Resume Next
    wks.UsedRange.Rows.Hidden = False
    On Error GoTo 0

    Application.EnableEvents = False
    Application.ScreenUpdating = False

    Debug.Print Timer() - d1

End Sub

Хорошо, вот пример использования Doc и Doc в словарах.Раньше я не был убежден, но, посмотрев на него, протестировав его и сравнив с расширенным фильтром, я убедился, что словари лучше подходят для этого приложения.Я не знаю, почему Excel не работает быстрее в этом вопросе, поскольку они должны использовать более быстрые алгоритмы, это не скрытие, не скрытие строк, поскольку это происходит очень быстро.Так что, если кто-нибудь знает, дайте мне знать.На моем медленном компьютере эта процедура занимает чуть более 1 секунды:

Sub FindDupesAndDelete()

    Dim d1 As Double
    Dim dict As Object
    Dim sh As Worksheet
    Dim v1 As Variant
'    Dim s1() As String
    Dim rDelete As Range
    Dim bUnion As Boolean

    d1 = Timer()
    bUnion = False
    Set dict = CreateObject("Scripting.Dictionary")
    Set sh = ActiveSheet
    v1 = Application.Transpose(sh.Range("A1", "A" _
          & sh.Cells.SpecialCells(xlCellTypeLastCell).row))

'    ReDim s1(1 To UBound(v1))

    Dim row As Long, value As String ', newEntry As Boolean
    For row = 1 To sh.Cells.SpecialCells(xlCellTypeLastCell).row
        value = v1(row)

        If dict.Exists(value) Then
'            newEntry = False
            If bUnion Then
                Set rDelete = Union(rDelete, sh.Range("A" & row))
            Else
                Set rDelete = sh.Range("A" & row)
                bUnion = True
            End If
        Else
'            newEntry = True
            dict.Add value, 1
        End If
'        s1(row) = newEntry

    Next
    rDelete.EntireRow.Delete
'    sh.Range("B1", "B" & UBound(v1)) = Application.Transpose(s1)
    Debug.Print Timer() - d1
End Sub
4 голосов
/ 30 августа 2011

Прежде чем начать заново весь код, вот несколько вещей, которые вы можете попробовать:

Оптимизируйте свой VBA В Интернете есть несколько советов по оптимизации vba.В частности, вы можете сделать:

'turn off some Excel functionality so your code runs faster
'these two are especially very efficient
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
'use these if you really need to
Application.DisplayStatusBar = False
Application.EnableEvents = False

'code goes here

'at the end, restore the default behavior
'calculate the formulas
Application.Calculate
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
Application.DisplayStatusBar = True
Application.EnableEvents = True

См. здесь для получения дополнительной информации

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

В части удаления строки, вы должны попробовать решение, которое я дал вам в вашей предыдущей теме: Удалить повторяющиеся записи вВ столбце Excel 2003 vba сначала выполнить фильтрацию по значениям True, а затем удалить видимые ячейки.Вероятно, это самый быстрый способ.

[EDIT] Похоже, что ответ Дока Брауна, вероятно, будет лучшим способом справиться с этим (эй, это словарное решение, которое не было написаноIssun :)).В любом случае, советы по оптимизации VBA все еще актуальны, потому что это довольно медленный язык.

3 голосов
/ 01 сентября 2011

Хорошо, теперь у нас есть дополнительная информация, вот решение. Это должно выполняться почти мгновенно.

Код работает, заполняя столбец y формулой конкатенации. Затем он добавляет весь столбец y в словарь и, используя словарь, помечает каждую строку как дубликат в столбце z. Затем он удаляет все дубликаты, найденные после строки 35000. Затем, наконец, он очищает и столбец y, и столбец z, чтобы удалить лишние данные.

Sub RemoveDuplicates()
    Dim vData As Variant, vArray As Variant
    Dim lRow As Long

    '// Get used range of column A (excluding header) and offset to get column y 
    With ActiveSheet.Range("A2", Cells(Rows.Count, "A").End(xlUp)).Offset(, 24)
        '// Adds the concatenate formula to the sheet column (y)
        .FormulaR1C1 = "=RC[-24]&RC[-23]&RC[-19]&RC[-18]&RC[-17]&RC[-16]"
        '// Adds the formula results to an array
        vData = .Resize(, 1).value
    End With

    '// Re dimension the array to the correct size 
    ReDim vArray(1 To UBound(vData, 1), 0)

    '// Create a dictionary object using late binding
    With CreateObject("Scripting.Dictionary")
        '// Loop through each row in the array
        For lRow = 1 To UBound(vData, 1)
            '// Check if value exists in the array
            If Not .exists(vData(lRow, 1)) Then
                '// Value does not exist mark as non duplicate.
                vArray(lRow, 0) = "x"
                '//  Add value to dictionary
                .Add vData(lRow, 1), Nothing
            End If
        Next lRow
    End With

    '// Turn off screen updating to speed up code and prevent screen flicker
    Application.ScreenUpdating = False    

    With ActiveSheet
        '// Populate column z with the array
        .Range("Z2").Resize(UBound(vArray, 1)) = vArray
        '// Use error handling as speciallcells throws an error when none exist.
        On Error Resume Next
        '// Delete all blank cells in column z
        .Range("Y35001", .Cells(Rows.Count, "Y").End(xlUp)).Offset(, 1).SpecialCells(xlCellTypeBlanks).EntireRow.Delete
        '// Remove error handling
        On Error GoTo 0
        '// Clear columns y and z
        .Columns(25).Resize(, 2).ClearContents
    End With

   '// Turn screen updating back on.
   Application.ScreenUpdating = True
End Sub

ПРИМЕЧАНИЕ. Вы можете изменить все ссылки "activesheet" на свое кодовое имя листа.

ПРИМЕЧАНИЕ 2. Предполагается, что у вас есть заголовки, и оставлена ​​только строка 1.

Я использовал ваши столбцы и тестовые данные как мог. Вот тестовая заливка, которую я использовал:

Sub TestFill()

    For i = 1 To 37000
        With Range("A" & i)
            .value = Choose(Int(2 * Rnd + 1), "PTY", "GTY")
            .Offset(, 1).value = Round((40000 * (Rnd + 1)), Choose(Int(4 * Rnd + 1), 1, 2, 3, 4))
            .Offset(, 5).value = Int(4 * Rnd + 1)
            .Offset(, 6).value = Int(2 * Rnd + 1)
            .Offset(, 7).value = Choose(Int(2 * Rnd + 1), "230", "540")
            .Offset(, 8).value = Int(3 * Rnd + 1)
        End With
    Next i

End Sub
2 голосов
/ 30 августа 2011

Допустим, у вас есть записи в столбце A, и вы хотите получить результат вашей формулы в столбце B (но намного быстрее).Этот макрос VBA должен выполнить свою задачу:

Option Explicit
Sub FindDupes()
    Dim dict As Object
    Dim sh As Worksheet
    Set dict = CreateObject("Scripting.Dictionary")
    Set sh = ActiveSheet

    Dim row As Long, value As String
    For row = 1 To sh.Cells.SpecialCells(xlCellTypeLastCell).row
        value = sh.Range("A" & row).Text
        If dict.Exists(value) Then
            sh.Range("B" & row) = "False"
        Else
            sh.Range("B" & row) = "True"
            dict.Add value, 1
        End If
    Next
End Sub

(Использование словаря дает здесь почти линейное время выполнения, которое должно составлять считанные секунды для 35,0000 строк, где ваша исходная формула имела квадратичную сложность времени выполнения).

Редактировать: из-за вашего комментария: сначала вам нужно будет заполнить словарь, прочитав каждую запись хотя бы один раз, чего вы не можете легко избежать.Чего можно избежать, так это снова заполнить строки столбца B, когда они уже заполнены:

Option Explicit
Sub FindDupes()
    Dim dict As Object
    Dim sh As Worksheet
    Set dict = CreateObject("Scripting.Dictionary")
    Set sh = ActiveSheet

    Dim row As Long, value As String, newEntry As Boolean
    For row = 1 To sh.Cells.SpecialCells(xlCellTypeLastCell).row
        value = sh.Range("A" & row).Text

        If dict.Exists(value) Then
            newEntry = False
        Else
            newEntry = True
            dict.Add value, 1
        End If
        If Trim(sh.Range("B" & row)) = "" Then sh.Range("B" & row) = newEntry
    Next
End Sub

Но я подозреваю, что это не будет намного быстрее, чем мое первое решение.

1 голос
/ 31 августа 2011

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

Sub RemoveNewDupes()

Application.ScreenUpdating = False
Dim lastRow As Long
Dim varray As Variant
Dim oldDict As Object, newDict As Object
Set oldDict = CreateObject("scripting.dictionary")
Set newDict = CreateObject("scripting.dictionary")

On Error Resume Next
lastRow = Range("A" & Rows.Count).End(xlUp).Row

'Add old entries to dictionary
varray = Range("A1:A35000").Value
For i = 1 To UBound(varray, 1)
    oldDict.Add varray(i, 1), 1
Next

'Check for dupes
varray = Range("A35001:A" & lastRow).Value
For i = 35000 + UBound(varray, 1) To 35001 Step -1
    If oldDict.exists(varray(i - 35000, 1)) = True Or _
       newDict.exists(varray(i - 35000, 1)) = True Then
        Range("A" & i).EntireRow.Delete
    Else
        newDict.Add varray(i - 35000, 1), 1
    End If
Next

Application.ScreenUpdating = True

'A status message at the end for finishing touch
MsgBox UBound(varray, 1) - newDict.Count & _
" duplicate row(s) found and deleted."

End Sub

Как это работает :

Сначала я сохраняю 35000 ячеек в словарефайл.Затем я беру вариантный массив каждой ячейки 35001 и перебираю их в обратном порядке, чтобы увидеть, находится ли он в словаре 35k или нет, или что мы еще не нашли значение в цикле.Если он находит, что это обман, он удаляет строку.

Классный (если я могу сказать) способ удаления строки заключается в том, что при создании массива, например, A35001 - A37000, он сохраняетих как (1, 1) (2, 1) (...).Таким образом, если вы установите «i» в Ubound массива + 35000 и вернетесь к 35001, вы переберите все добавления в обратном направлении от A37000 до A35001.Затем, когда вы хотите удалить строку, «i» идеально соответствует номеру строки, в которой было найдено значение, так что вы можете удалить его.И поскольку он идет в обратном направлении, он не замыкает петлю!

...