Добрый день! Меня преследует гигантомания У меня есть две массива с данными. В примере в первом массиве 30 строк во втором 152. И те данные, что в первом (столбец С) Сравниваются с теми, что во втором и выводятся соответсвующие значения [vba]
Код
Sub cvbn() ar = Cells(Rows.Count, "C").End(xlUp).Row For i = 2 To ar Set FCell = Columns("I:I").Find(Cells(i, "C")) If Not FCell Is Nothing Then Cells(i, "D") = FCell.Offset(0, 1) Cells(i, "E") = FCell.Offset(0, 2) Cells(i, "F") = FCell.Offset(0, 3) End If Next i End Sub
[/vba] Все здорово, пока не запускается код на полном файле, где в первом массиве 700 000 строк, а во втором 15 000. Раньше, когда я делал все руками: искал эти совпадения ВПР'ом, Формула работала минут 20. Сначала я запустил все циклом и ощутил всю тягость на моем i7 и наглухо зависший эксель пришлось тупо отрубить. Решил попробовать через find: стало все получше, даже файл не завис, и половину обработал, но опять же процесс был существенно более долгим, чем формульная впр. Как можно ускорить обработку таких массивов?
Добрый день! Меня преследует гигантомания У меня есть две массива с данными. В примере в первом массиве 30 строк во втором 152. И те данные, что в первом (столбец С) Сравниваются с теми, что во втором и выводятся соответсвующие значения [vba]
Код
Sub cvbn() ar = Cells(Rows.Count, "C").End(xlUp).Row For i = 2 To ar Set FCell = Columns("I:I").Find(Cells(i, "C")) If Not FCell Is Nothing Then Cells(i, "D") = FCell.Offset(0, 1) Cells(i, "E") = FCell.Offset(0, 2) Cells(i, "F") = FCell.Offset(0, 3) End If Next i End Sub
[/vba] Все здорово, пока не запускается код на полном файле, где в первом массиве 700 000 строк, а во втором 15 000. Раньше, когда я делал все руками: искал эти совпадения ВПР'ом, Формула работала минут 20. Сначала я запустил все циклом и ощутил всю тягость на моем i7 и наглухо зависший эксель пришлось тупо отрубить. Решил попробовать через find: стало все получше, даже файл не завис, и половину обработал, но опять же процесс был существенно более долгим, чем формульная впр. Как можно ускорить обработку таких массивов?AVI
Здравствуйте. Попробуйте на массивах сделать. Должно быть быстрее [vba]
Код
Sub cvbn() Dim x1, x2 Application.ScreenUpdating = False ar1 = Cells(Rows.Count, "C").End(xlUp).Row x1 = Range("C2:F" & ar1).Value ar2 = Cells(Rows.Count, "I").End(xlUp).Row x2 = Range("I2:L" & ar2).Value For i = 1 To UBound(x1) For j = 1 To UBound(x2) If x1(i, 1) = x2(j, 1) Then x1(i, 2) = x2(j, 2) x1(i, 3) = x2(j, 3) x1(i, 4) = x2(j, 4) Exit For End If Next j Next i Range("C2:F" & ar1) = x1 Application.ScreenUpdating = True End Sub
[/vba]
Здравствуйте. Попробуйте на массивах сделать. Должно быть быстрее [vba]
Код
Sub cvbn() Dim x1, x2 Application.ScreenUpdating = False ar1 = Cells(Rows.Count, "C").End(xlUp).Row x1 = Range("C2:F" & ar1).Value ar2 = Cells(Rows.Count, "I").End(xlUp).Row x2 = Range("I2:L" & ar2).Value For i = 1 To UBound(x1) For j = 1 To UBound(x2) If x1(i, 1) = x2(j, 1) Then x1(i, 2) = x2(j, 2) x1(i, 3) = x2(j, 3) x1(i, 4) = x2(j, 4) Exit For End If Next j Next i Range("C2:F" & ar1) = x1 Application.ScreenUpdating = True End Sub
Sub tt() Application.ScreenUpdating = 0 Application.Calculation = 3 r0_ = 2 ' n1_ = Cells(Rows.Count, 3).End(3).Row - r0_ + 1 n2_ = Cells(Rows.Count, 9).End(3).Row - r0_ + 1 Cells(r0_, 4).Resize(n1_, 3).Clear ar1 = Cells(r0_, 3).Resize(n1_, 4) ar2 = Cells(r0_, 9).Resize(n2_, 4) Set slov = CreateObject("Scripting.Dictionary") With slov For i = 1 To n2_ .Item(ar2(i, 1)) = i Next i For j = 1 To n1_ If .exists(ar1(j, 1)) Then s_ = .Item(ar1(j, 1)) For k = 2 To 4 ar1(j, k) = ar2(s_, k) Next k End If Next j End With Cells(r0_, 3).Resize(n1_, 4) = ar1 Application.Calculation = 1 Application.ScreenUpdating = 1 End Sub
[/vba]
А я бы на словаре сделал [vba]
Код
Sub tt() Application.ScreenUpdating = 0 Application.Calculation = 3 r0_ = 2 ' n1_ = Cells(Rows.Count, 3).End(3).Row - r0_ + 1 n2_ = Cells(Rows.Count, 9).End(3).Row - r0_ + 1 Cells(r0_, 4).Resize(n1_, 3).Clear ar1 = Cells(r0_, 3).Resize(n1_, 4) ar2 = Cells(r0_, 9).Resize(n2_, 4) Set slov = CreateObject("Scripting.Dictionary") With slov For i = 1 To n2_ .Item(ar2(i, 1)) = i Next i For j = 1 To n1_ If .exists(ar1(j, 1)) Then s_ = .Item(ar1(j, 1)) For k = 2 To 4 ar1(j, k) = ar2(s_, k) Next k End If Next j End With Cells(r0_, 3).Resize(n1_, 4) = ar1 Application.Calculation = 1 Application.ScreenUpdating = 1 End Sub
Что-то долго он у Вас. У меня отрабатывает в среднем за 1,5 секунды (машинке уже лет 6) Можно немного ускорить, не меняя логику [vba]
Код
Sub tt1() t_ = Timer Application.ScreenUpdating = 0 Application.Calculation = 3 r0_ = 2 ' n1_ = Cells(Rows.Count, 3).End(3).Row - r0_ + 1 n2_ = Cells(Rows.Count, 9).End(3).Row - r0_ + 1 ar1 = Cells(r0_, 3).Resize(n1_) ar11 = Cells(r0_, 9999).Resize(n1_, 3) ar2 = Cells(r0_, 9).Resize(n2_, 4) Set slov = CreateObject("Scripting.Dictionary") With slov For i = 1 To n2_ .Item(ar2(i, 1)) = i Next i For j = 1 To n1_ If .exists(ar1(j, 1)) Then s_ = .Item(ar1(j, 1)) For k = 2 To 4 ar11(j, k - 1) = ar2(s_, k) Next k End If Next j End With Cells(r0_, 4).Resize(n1_, 3) = ar11 Application.Calculation = 1 Application.ScreenUpdating = 1 MsgBox Timer - t_ End Sub
Что-то долго он у Вас. У меня отрабатывает в среднем за 1,5 секунды (машинке уже лет 6) Можно немного ускорить, не меняя логику [vba]
Код
Sub tt1() t_ = Timer Application.ScreenUpdating = 0 Application.Calculation = 3 r0_ = 2 ' n1_ = Cells(Rows.Count, 3).End(3).Row - r0_ + 1 n2_ = Cells(Rows.Count, 9).End(3).Row - r0_ + 1 ar1 = Cells(r0_, 3).Resize(n1_) ar11 = Cells(r0_, 9999).Resize(n1_, 3) ar2 = Cells(r0_, 9).Resize(n2_, 4) Set slov = CreateObject("Scripting.Dictionary") With slov For i = 1 To n2_ .Item(ar2(i, 1)) = i Next i For j = 1 To n1_ If .exists(ar1(j, 1)) Then s_ = .Item(ar1(j, 1)) For k = 2 To 4 ar11(j, k - 1) = ar2(s_, k) Next k End If Next j End With Cells(r0_, 4).Resize(n1_, 3) = ar11 Application.Calculation = 1 Application.ScreenUpdating = 1 MsgBox Timer - t_ End Sub
Так я тоже сделал массивы на 15000 и 700000. Ну ладно, не принципиально
* А, ну правильно, я второй массив-то сделал из повторяющихся значений, а нужно было уникальные. Тогда словарь заполняется на все 700000 и это, конечно же, дольше. Полминуты примерно на стареньком i3 Интересно будет проверить на работе на хорошей машине. Если не забуду
Так я тоже сделал массивы на 15000 и 700000. Ну ладно, не принципиально
* А, ну правильно, я второй массив-то сделал из повторяющихся значений, а нужно было уникальные. Тогда словарь заполняется на все 700000 и это, конечно же, дольше. Полминуты примерно на стареньком i3 Интересно будет проверить на работе на хорошей машине. Если не забуду_Boroda_
Интересно будет проверить на работе на хорошей машине. Если не забуду
3,17 У меня все)
И подскажите, что за строчка добавилась во втором варианте? Если все остальное я примерно понял, то эта строчка. Куда-то на 9999 столбец что-то заливается, но там ничего нет...
Интересно будет проверить на работе на хорошей машине. Если не забуду
3,17 У меня все)
И подскажите, что за строчка добавилась во втором варианте? Если все остальное я примерно понял, то эта строчка. Куда-то на 9999 столбец что-то заливается, но там ничего нет...AVI
Сообщение отредактировал AVI - Воскресенье, 07.10.2018, 06:36
Не заливается, а оттуда забирается пустой массив. Чтобы не стирать столбцы D:F. Берем пустой массив из пустых ячеек далеко сбоку справа, заполняем его по алгоритму и вставляем в D:F
3,17 - это что? Время вместо 12 секунд?
Не заливается, а оттуда забирается пустой массив. Чтобы не стирать столбцы D:F. Берем пустой массив из пустых ячеек далеко сбоку справа, заполняем его по алгоритму и вставляем в D:F
Добрый день, в своей работе данный макрос использую для поиска по списку "Словарь" - это то, что ищем, в вашем случае это список из колонки "с"
[vba]
Код
Private Sub SearchByList() '' Author: boa '' Written: 20.10.2017 '' Edited: ' Description: Берет данные из заданного диапазона искомых значений(Словаря) и сравнивает их со списком значений, ' если находит совпадения, то переносит все уникальные значения из заданного столбца ' и сопоставленное ему значение из Словаря в новую книгу.
Dim MyList As Range 'Список искомых значений Dim MyRange As Range 'Диапазон для поиска Dim SearchColumn As Integer 'колонка в которой ищем совпадения Dim ZnachColumn As Integer 'колонка из которой нужно вывести значения Dim iRow&, V$, Znach As Variant Dim strCaption$, strLabel$
On Error GoTo Proverka strCaption = "Поиск уникальных значений по списку" strLabel = "Введите ссылку на список значений которые надо найти(Словарь)." & vbCrLf & _ "Будут учитываться только видимы значения из выбранного диапазона." Set MyList = Application.InputBox(Prompt:=strLabel, Title:=strCaption, Type:=8) strLabel = "Введите ссылку на диапазон содержащий искомые значения и колонку для сопоставления со Словарем." Set MyRange = Application.InputBox(Prompt:=strLabel, Title:=strCaption, Type:=8) If Not MyRange Is Nothing Then SearchColumn = MyRange.Columns.Count strLabel = "Введите номер колонки от 1 до " & SearchColumn & " в выбранном диапазоне, по которой должен быть произведен поиск значений из Словаря." SearchColumn = Application.InputBox(Prompt:=strLabel, Title:=strCaption, Default:=SearchColumn, Type:=1)
strLabel = "Введите номер колонки в массиве из которой надо вывести найденный результат." & vbCrLf & _ "Если номер колонки не вводить(нажать ""Отмена""), то в результат будет выведена вся строка из выделенного диапазона." ZnachColumn = Application.InputBox(Prompt:=strLabel, Title:=strCaption, Type:=1) Proverka: If MyList Is Nothing Or MyRange Is Nothing Or SearchColumn < 1 Then _ MsgBox "Не введены все обязательные параметры для поиска значений.", vbCritical, "": Exit Sub
Dim Start!, sMsg$ Start! = Timer
Dim i&, a As Range, DicSearch As Object, Dic As Object
Set DicSearch = CreateObject("Scripting.Dictionary") Set Dic = CreateObject("Scripting.Dictionary") ' DicSearch.CompareMode = vbTextCompare ' Dic.CompareMode = vbTextCompare 'Что бы сделать ключи не чуствительными к регистру. _ ' vbBinaryCompare - по умолчанию. "File", "FILE" и "file" три разных ключа
On Error Resume Next For Each a In MyList 'Список искомых значений If a.Rows.Hidden = False Then DicSearch.Add CStr(a.Value), a.Value Next a
For i = 1 To MyRange.Rows.Count 'Список найденных значений If DicSearch.Exists(CStr(MyRange.Cells(i, SearchColumn).Value)) Then If ZnachColumn > 0 Then V = CStr(MyRange.Cells(i, ZnachColumn).Value) Else V = i Dic.Add V, CStr(MyRange.Cells(i, SearchColumn).Value) End If Next i
With Workbooks.Add(xlWBATWorksheet).Worksheets(1) 'вывод результатов .Cells(1, 1).Value = "Значения из списка" .Cells(1, 2).Value = "Найденные значение " & Dic.Count iRow = 2 If ZnachColumn > 0 Then .Range(.Cells(iRow, 1), .Cells(Dic.Count + 1, 2)).Value = Application.Transpose(Array(Dic.Items, Dic.Keys)) Else .Range(.Cells(iRow, 1), .Cells(Dic.Count + 1, 1)).Value = Application.Transpose(Array(Dic.Items)) For Each Znach In Dic .Range(.Cells(iRow, 2), .Cells(iRow, MyRange.Columns.Count + 1)).Value = MyRange.Rows(Znach).Value iRow = iRow + 1 Next End If .UsedRange.EntireColumn.AutoFit End With
Добрый день, в своей работе данный макрос использую для поиска по списку "Словарь" - это то, что ищем, в вашем случае это список из колонки "с"
[vba]
Код
Private Sub SearchByList() '' Author: boa '' Written: 20.10.2017 '' Edited: ' Description: Берет данные из заданного диапазона искомых значений(Словаря) и сравнивает их со списком значений, ' если находит совпадения, то переносит все уникальные значения из заданного столбца ' и сопоставленное ему значение из Словаря в новую книгу.
Dim MyList As Range 'Список искомых значений Dim MyRange As Range 'Диапазон для поиска Dim SearchColumn As Integer 'колонка в которой ищем совпадения Dim ZnachColumn As Integer 'колонка из которой нужно вывести значения Dim iRow&, V$, Znach As Variant Dim strCaption$, strLabel$
On Error GoTo Proverka strCaption = "Поиск уникальных значений по списку" strLabel = "Введите ссылку на список значений которые надо найти(Словарь)." & vbCrLf & _ "Будут учитываться только видимы значения из выбранного диапазона." Set MyList = Application.InputBox(Prompt:=strLabel, Title:=strCaption, Type:=8) strLabel = "Введите ссылку на диапазон содержащий искомые значения и колонку для сопоставления со Словарем." Set MyRange = Application.InputBox(Prompt:=strLabel, Title:=strCaption, Type:=8) If Not MyRange Is Nothing Then SearchColumn = MyRange.Columns.Count strLabel = "Введите номер колонки от 1 до " & SearchColumn & " в выбранном диапазоне, по которой должен быть произведен поиск значений из Словаря." SearchColumn = Application.InputBox(Prompt:=strLabel, Title:=strCaption, Default:=SearchColumn, Type:=1)
strLabel = "Введите номер колонки в массиве из которой надо вывести найденный результат." & vbCrLf & _ "Если номер колонки не вводить(нажать ""Отмена""), то в результат будет выведена вся строка из выделенного диапазона." ZnachColumn = Application.InputBox(Prompt:=strLabel, Title:=strCaption, Type:=1) Proverka: If MyList Is Nothing Or MyRange Is Nothing Or SearchColumn < 1 Then _ MsgBox "Не введены все обязательные параметры для поиска значений.", vbCritical, "": Exit Sub
Dim Start!, sMsg$ Start! = Timer
Dim i&, a As Range, DicSearch As Object, Dic As Object
Set DicSearch = CreateObject("Scripting.Dictionary") Set Dic = CreateObject("Scripting.Dictionary") ' DicSearch.CompareMode = vbTextCompare ' Dic.CompareMode = vbTextCompare 'Что бы сделать ключи не чуствительными к регистру. _ ' vbBinaryCompare - по умолчанию. "File", "FILE" и "file" три разных ключа
On Error Resume Next For Each a In MyList 'Список искомых значений If a.Rows.Hidden = False Then DicSearch.Add CStr(a.Value), a.Value Next a
For i = 1 To MyRange.Rows.Count 'Список найденных значений If DicSearch.Exists(CStr(MyRange.Cells(i, SearchColumn).Value)) Then If ZnachColumn > 0 Then V = CStr(MyRange.Cells(i, ZnachColumn).Value) Else V = i Dic.Add V, CStr(MyRange.Cells(i, SearchColumn).Value) End If Next i
With Workbooks.Add(xlWBATWorksheet).Worksheets(1) 'вывод результатов .Cells(1, 1).Value = "Значения из списка" .Cells(1, 2).Value = "Найденные значение " & Dic.Count iRow = 2 If ZnachColumn > 0 Then .Range(.Cells(iRow, 1), .Cells(Dic.Count + 1, 2)).Value = Application.Transpose(Array(Dic.Items, Dic.Keys)) Else .Range(.Cells(iRow, 1), .Cells(Dic.Count + 1, 1)).Value = Application.Transpose(Array(Dic.Items)) For Each Znach In Dic .Range(.Cells(iRow, 2), .Cells(iRow, MyRange.Columns.Count + 1)).Value = MyRange.Rows(Znach).Value iRow = iRow + 1 Next End If .UsedRange.EntireColumn.AutoFit End With