Доброго вечера, Планетяне! В прошлой своей теме более-менее разобрался с созданием UDF'ок начального уровня. Теперь же вопрос глобальный и серьёзный. Увидел тут статью на тему мегаускорения ВПР'а (или связки ИНДЕКС+ПОИСКПОЗ) за счёт "неточного" поиска. Есть, правда, нюанс — столбец поиска должен быть отсортирован по возрастанию. На Планете нашёл тему, в которой этот вопрос решён. Однако, это для отсортированного массива и лучший ли это вариант для Excel? Можно ли ещё как-то ускорить и как сортировать массив в коде? Прошу писать свои наработки и просто советы на тему. Файл-пример прилагается (большой, поскольку 2 столбца по 500к строк). Маленький пример тут в посте. Данные в примерах - рандомная генерация
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
По названию темы: в ВПР неприменим бинарный поиск при несортированных данных. Все? Тема закрыта? Или вопрос о сортировку в массиве?
Цитата
Файл-пример... большой
Т.е. для примера совсем никак нельзя 100 строк, а проверять потом на своем в 500К? Через время ссылки стают недоступны, темы остаются без файлов. Неужели этого не знали?
Максим Зеленский, если данные неотсортированы, то будет ли прирост скорости при сортировке массива внутри UDF и дальнейшем использовании бинарного поиска через ВПР или ИНДЕКС+ПОИСКПОЗ.
vikttur, по этому названию желающие без проблем найдут тему. А если в название подтягивать всю "простыню" с предысторией и вариантами, то никто и никогда тему не найдёт, а если и найдёт, то не откроет, испугавшись названия - я так думаю. Смысл темы в написании наибыстрейшей UDF по поиску и подтягиванию соответствий. Так как бинарный поиск (дающий огромный прирост в скорости) осуществим только с отсортированными данными, смысл темы сводится к поиску оптимального из способов приведения исходных данных к отсортированному виду (типа макроса по сортировке таблицы или же сортировке массива внутри UDF). Про файл-пример: я не разобрался, как тестить внутри кода. Такой объём сделал для теста "в лоб" с секундомером в руке))) средневековье, однако, но что делать… Добавлю маленький пример.
Не хотел давать название о сортировке, потому что интересны опыт и мысли людей в целом. Может кто-то предложит вообще другой вариант…
Возможное новое название темы:«Бинарный поиск в Excel. Как искать быстро.»
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Jack Famous написал: Можно ли ещё как-то ускорить и как сортировать массив в коде?
да, написать свою библу(где используются linq и бинарный поиск(первое, что пришло в голову)), передавать ей параметры и получать результат. И это для реально больших массивов. А так, все эти ускоренные поиски в excel от лукавого. В темы я не вдавался, но мне хватает find
а какой из этих кодов с Find будет быстрее, как вы считаете?
Код
Function BPR3(What As Range, Where As Range) As Range
If WorksheetFunction.CountIf(Where.Columns(1), What) = 0 Then Exit Function
Set BPR3 = Where.Columns(1).Find(What, Where.Cells(1), xlValues, xlWhole).Offset(0, 1)
End Function
'=====================================================================================
Function ПодтянутьСПроверками_ПОИСК(что_ищем As Variant, ByRef где_ищем As Range, ByRef откуда_берём As Range) As Variant
Dim fr&, ofs&
fr = где_ищем.Find(что_ищем, где_ищем.Cells(1), xlValues, xlWhole).Row - 1
ofs = откуда_берём.Column - где_ищем.Column
ПодтянутьСПроверками_ПОИСК = откуда_берём(fr).Value
End Function
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
vikttur, нужен самый быстрый способ подтягивать значения по ключу интернет говорит, что этот способ - бинарный поиск. А вот уже для того, чтобы этот бинарный поиск мог работать, данные должны быть отсортированы по возрастанию
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Эта тема сродни мануалу как почесать левое ухо правой рукой через голову ... что значит самый быстрый? Это очень относительное понятие ... Если в массиве ключ будет первым, то прямой перебор будет быстрее бинарного поиска ... и наоборот. Вообще функция ВПР и так не медленная, зачем еще ее насиловать?
Цитата
Jack Famous написал: А вот уже для того, чтобы этот бинарный поиск мог работать, данные должны быть отсортированы по возрастанию
следовательно название темы ни о чем. Вас интересует сортировка массива, так и нужно называть тему... Но такие вопросы уже были и Слэн реализовал очень шустрый алгоритм сортировки больших массивов.
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Jack Famous написал: а какой из этих кодов с Find будет быстрее, как вы считаете?
Jack Famous, это уже некрасиво. "Свистни Ваня, ты глупее"?. Берите и проверяйте на своих файлах, это же Вам надо(во всяком случае Вы считаете, что надо). А то чуть ли не во всех темах советы гостям раздаете, три года на форуме, но такой пустяк самостоятельно осилить не можете.
kuklp написал: советы гостям раздаете, три года на форуме, но такой пустяк самостоятельно осилить не можете
ну, знаете, для кого пустяк, а для кого нет. Вот, будь для меня пустяк - я бы подсказал, помог (что и пытаюсь делать "чуть ли не во всех темах" и, иногда не в тему). А, извините, 3 года на форуме - это не 3 года обучения VBA. Почему некрасиво не понимаю. Если человек знает, например, что Offset быстрее индекса, почему бы не ответить. А, если не знает/не сталкивался, то на нет и суда нет… И вообще "за спрос не дают в нос", а вы вот даёте — вот что несправедливо. Профессионал высочайшего уровня, между прочим.
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Причем тут это знает\незнает? На форуме полно примеров измерения времени выполнения макросов. Кто Вам не дает замерить и сравнить? Но Вы грузите других. Это и некрасиво.
kuklp, есть у меня этипримеры - ну не разобрался я в них, пока что… Я же не требую (боже упаси - ни в коем случае) ответа. Знаете, что я часто вижу на форуме? Кто-то спрашивает, как ускорить макрос и опытный VBA'шник говорит: «да нафига ты вообще используешь вот это и вот это - это "тяжёлые" штуки и от них никакой пользы. Используй лучше вот это» вот об этом я и говорю - о быстром совете, основанном на многолетнем опыте. Я же, хоть и давно на форуме, но недалеко от новичков ушёл, т.к. работаю на стройке и VBA это просто способ повысить качество работы. Не судите строго, пожалуйста…
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
kuklp, тогда вы самый прошаренный сварщик из мне известных))) что ж — буду разбираться и ждать ответов, вдруг кому интересно. А не получится, тогда буду думать о связке через PQ, Access, SQL (в нём уже и так всё оптимизировано по поиску) и иже с ними
Кажется, я нашёл (правда в архиве) сортировку Слэма
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Раз уж тема уходит в сторону сортировки, то поделюсь самыми интересными кодами, на мой взгляд:
Слэн
Код
'Сортировка массива
'Автор: Слэн
'Тема на форуме: http://www.planetaexcel.ru/forum/index.php?PAGE_NAME=message&FID=8&TID=26414&MID=231854#message231854
'===========================================================================================================================
Private Type QuickStack
'тип для QuickSort
Low As Long
High As Long
End Type
Public Sub QuickSortNonRecursive___(SortArray())
Dim i As Long, j As Long, lb As Long, ub As Long
Dim stack() As QuickStack, stackpos As Long, ppos As Long, pivot As Variant, swp, maxstack&
On Error GoTo er
ReDim stack(1 To 16)
stackpos = 1
stack(1).Low = LBound(SortArray)
stack(1).High = UBound(SortArray)
Do
'Взять границы lb и ub текущего массива из стека.
lb = stack(stackpos).Low
ub = stack(stackpos).High
stackpos = stackpos - 1
Do
'Шаг 1. Разделение по элементу pivot
ppos = (lb + ub) \ 2
i = lb: j = ub: pivot = SortArray(ppos)
Do
While SortArray(i) < pivot: i = i + 1: Wend
While pivot < SortArray(j): j = j - 1: Wend
If i > j Then Exit Do
' If i <> j Then
swp = SortArray(i): SortArray(i) = SortArray(j): SortArray(j) = swp
' End If
i = i + 1
j = j - 1
' End If
Loop While i <= j
'Сейчас указатель i указывает на начало правого подмассива,
'j - на конец левого lb ? j ? i ? ub.
'Возможен случай, когда указатель i или j выходит за границу массива
'Шаги 2, 3. Отправляем большую часть в стек и двигаем lb,ub
If i < ppos Then 'правая часть больше
If i < ub Then
stackpos = stackpos + 1
stack(stackpos).Low = i
stack(stackpos).High = ub
End If
ub = j 'следующая итерация разделения будет работать с левой частью
Else
If j > lb Then
stackpos = stackpos + 1
stack(stackpos).Low = lb
stack(stackpos).High = j
End If
lb = i
End If
' If maxstack < stackpos Then maxstack = stackpos
Loop While lb < ub
Loop While stackpos
Exit Sub
er: ReDim Preserve stack(1 To UBound(stack) * 2)
Resume
' Debug.Print maxstack
End Sub
'===========================================================================================================================
Public Sub QuickSortNonRecursive_i(ByRef SortArray(), ByRef r() As Long, Optional ByVal col = 1)
Dim i As Long, j As Long, lb As Long, ub As Long
Dim stack() As QuickStack, stackpos As Long, ppos As Long, pivot As Variant, swp, maxstack&
On Error GoTo er
lb = LBound(SortArray)
ub = UBound(SortArray)
For i = lb To ub
r(i) = i
Next
ReDim stack(1 To 16)
stackpos = 1
stack(1).Low = lb
stack(1).High = ub
Do
'Взять границы lb и ub текущего массива из стека.
lb = stack(stackpos).Low
ub = stack(stackpos).High
stackpos = stackpos - 1
Do
'Шаг 1. Разделение по элементу pivot
ppos = (lb + ub) \ 2
i = lb: j = ub: pivot = SortArray(ppos, col)
Do
While SortArray(i, col) < pivot: i = i + 1: Wend
While pivot < SortArray(j, col): j = j - 1: Wend
If i > j Then Exit Do
' If i <> j Then
swp = SortArray(i, col): SortArray(i, col) = SortArray(j, col): SortArray(j, col) = swp
swp = r(i): r(i) = r(j): r(j) = swp
' End If
i = i + 1
j = j - 1
' End If
Loop While i <= j
'Сейчас указатель i указывает на начало правого подмассива,
'j - на конец левого lb ? j ? i ? ub.
'Возможен случай, когда указатель i или j выходит за границу массива
'Шаги 2, 3. Отправляем большую часть в стек и двигаем lb,ub
If i < ppos Then 'правая часть больше
If i < ub Then
stackpos = stackpos + 1
stack(stackpos).Low = i
stack(stackpos).High = ub
End If
ub = j 'следующая итерация разделения будет работать с левой частью
Else
If j > lb Then
stackpos = stackpos + 1
stack(stackpos).Low = lb
stack(stackpos).High = j
End If
lb = i
End If
' If maxstack < stackpos Then maxstack = stackpos
Loop While lb < ub
Loop While stackpos
Exit Sub
er: ReDim Preserve stack(1 To UBound(stack) * 2)
Resume
' Debug.Print maxstack
End Sub
'===========================================================================================================================
Public Sub QuickSortNonRecursive_2(ByRef SortArray(), Optional ByVal col = 1)
On Error Resume Next
If UBound(SortArray, 2) > 2 Then Exit Sub
Dim i As Long, j As Long, lb As Long, ub As Long, dc&
Dim stack() As QuickStack, stackpos As Long, ppos As Long, pivot As Variant, swp, maxstack&
On Error GoTo er
lb = LBound(SortArray)
ub = UBound(SortArray)
dc = UBound(SortArray, 2) + 1 - col
ReDim stack(1 To 16)
stackpos = 1
stack(1).Low = lb
stack(1).High = ub
Do
'Взять границы lb и ub текущего массива из стека.
lb = stack(stackpos).Low
ub = stack(stackpos).High
stackpos = stackpos - 1
Do
'Шаг 1. Разделение по элементу pivot
ppos = (lb + ub) \ 2
i = lb: j = ub: pivot = SortArray(ppos, col)
Do
While SortArray(i, col) < pivot: i = i + 1: Wend
While pivot < SortArray(j, col): j = j - 1: Wend
If i > j Then Exit Do
' If i <> j Then
swp = SortArray(i, col): SortArray(i, col) = SortArray(j, col): SortArray(j, col) = swp
swp = SortArray(i, dc): SortArray(i, dc) = SortArray(j, dc): SortArray(j, dc) = swp
' End If
i = i + 1
j = j - 1
' End If
Loop While i <= j
'Сейчас указатель i указывает на начало правого подмассива,
'j - на конец левого lb ? j ? i ? ub.
'Возможен случай, когда указатель i или j выходит за границу массива
'Шаги 2, 3. Отправляем большую часть в стек и двигаем lb,ub
If i < ppos Then 'правая часть больше
If i < ub Then
stackpos = stackpos + 1
stack(stackpos).Low = i
stack(stackpos).High = ub
End If
ub = j 'следующая итерация разделения будет работать с левой частью
Else
If j > lb Then
stackpos = stackpos + 1
stack(stackpos).Low = lb
stack(stackpos).High = j
End If
lb = i
End If
' If maxstack < stackpos Then maxstack = stackpos
Loop While lb < ub
Loop While stackpos
Exit Sub
er: ReDim Preserve stack(1 To UBound(stack) * 2)
Resume
' Debug.Print maxstack
End Sub
'===========================================================================================================================
Sub sort_range(ByRef arr(), Optional ByVal col& = 1)
Dim nu&, nl&, i&, j&, rl&, ru&, i_arr&(), rez()
On Error GoTo er1
nu = UBound(arr, 2)
nl = LBound(arr, 2)
On Error GoTo er2
rl = LBound(arr)
ru = UBound(arr)
If (nu - nl) = 1 Then
Call QuickSortNonRecursive_2(arr, col)
Else
ReDim i_arr(rl To ru)
rez = arr
Call QuickSortNonRecursive_i(arr, i_arr, col)
For i = rl To ru
For j = nl To col - 1
arr(i, j) = rez(i_arr(i), j)
Next
For j = col + 1 To nu
arr(i, j) = rez(i_arr(i), j)
Next
Next
End If
Exit Sub
er1: Call QuickSortNonRecursive___(arr)
Exit Sub
er2: MsgBox "Не массив"
End Sub
'Sub t()
'Dim arr(1 To 9, 1 To 3), r
'r = [a1:c9]
'For i = 1 To 9
'For j = 1 To 3
'arr(i, j) = r(i, j)
'Next
'Next
'Call sort_range(arr)
'[a1:c9] = arr
'End Sub
nerv
Код
'Author: nerv
'E-mail: nerv-net@yandex.ru
'Last Update: 01/12/2011
'??????.??????: 41001156540584
'Тема на форуме: http://www.planetaexcel.ru/forum/index.php?PAGE_NAME=read&FID=8&TID=6998
'===============================================================================================================
Private Sub LiteSort(ByRef x())
Dim v, u&, d&, f%
If IsArray(x) Then
f = LBound(x): d = f
For u = f + 1 To UBound(x)
If x(u) < x(d) Then
v = x(d): x(d) = x(u): x(u) = v
u = d - 1: d = u - 1: If u < f Then d = u: u = f
End If
d = d + 1
Next
End If
End Sub
'Пример:
'Sub Example()
'Dim x()
'x = Array(9, 3, 8, 1, 6)
'LiteSort x()
'End Sub
excelvba
Код
'Сортировки двумерного массива
'Ссылка: http://excelvba.ru/code/SortArray
'===============================================================================================================
'Сортировка внутри VBA
'===============================================================================================================
Function CoolSort(SourceArr As Variant, ByVal N As Integer) As Variant
' сортировка двумерного массива по столбцу N
If N > UBound(SourceArr, 2) Or N < LBound(SourceArr, 2) Then _
MsgBox "Нет такого столбца в массиве!", vbCritical: Exit Function
Dim Check As Boolean, iCount As Integer, jCount As Integer, nCount As Integer
ReDim tmpArr(UBound(SourceArr, 2)) As Variant
Do Until Check
Check = True
For iCount = LBound(SourceArr, 1) To UBound(SourceArr, 1) - 1
If Val(SourceArr(iCount, N)) > Val(SourceArr(iCount + 1, N)) Then
For jCount = LBound(SourceArr, 2) To UBound(SourceArr, 2)
tmpArr(jCount) = SourceArr(iCount, jCount)
SourceArr(iCount, jCount) = SourceArr(iCount + 1, jCount)
SourceArr(iCount + 1, jCount) = tmpArr(jCount)
Check = False
Next
End If
Next
Loop
CoolSort = SourceArr
End Function
'===============================================================================================================
'Сортировка на листе временной книги
'===============================================================================================================
Function SortArrayOnExcelWorksheet(ByRef arr) As Boolean
On Error Resume Next: Err.Clear
' возвращает FALSE, если массив не поддается сортировке (не влазит на лист Excel)
Application.ScreenUpdating = False
Dim WB As Workbook, sh As Worksheet, ra As Range
Set WB = Workbooks.Add(xlWBATWorksheet)
If WB Is Nothing Then Exit Function
Set sh = WB.Worksheets(1)
Set ra = sh.Range("a1").Resize(UBound(arr, 1), UBound(arr, 2))
ra.FormulaR1C1Local = arr
If Err Then Debug.Print "Ошибка вставки массива для сортировки на лист": WB.Close False: Exit Function
ra.Sort ra.Cells(1), 1, ra.Cells(2), , 1, ra.Cells(3), 1, xlNo ' сортировка массива
If Err Then Debug.Print "Ошибка сортировки массива": WB.Close False: Exit Function
arr = ra.FormulaR1C1Local
SortArrayOnExcelWorksheet = True
WB.Close False
End Function
'Пример: SortArrayOnExcelWorksheet arr
'===============================================================================================================
'Пузырьковая сортировка одномерного массива «arr»
'===============================================================================================================
Public Sub BubbleSort(ByRef arr)
N = UBound(arr)
For i = 0# To N - 1# Step 1
For j = 0# To N - 2# - i Step 1
If arr(j) > arr(j + 1#) Then
tmp = arr(j)
arr(j) = arr(j + 1#)
arr(j + 1#) = tmp
End If
Next j
Next i
End Sub
'===============================================================================================================
'то же, но внутри макроса
'===============================================================================================================
For i& = LBound(arr) To UBound(arr) - 1
For j& = LBound(arr) To UBound(arr) - 2 - i
If arr(j) > arr(j + 1) Then tmp = arr(j): arr(j) = arr(j + 1): arr(j + 1) = tmp
Next j
Next i
Что касается "подтягивания по ключу", придумал несколько костылей/решений: 1. Использовать макрос вместо макрофункции, который сортирует словарь на листе по возрастанию и, затем, (после парочки проверок) использует ИНДЕКС+ПОИСКПОЗ (с 4ым параметром=1) для проставления значений. 2. Вообще избавиться от необходимости поиска по словарю за счёт связывания таблиц между собой по ключам через PQ (или другие решения)
Вообще, в процессе поиска ответов на мои вопросы, среди всевозможных супероптимальных сортировок массивов и уникальных алгоритмов уловил (так это или нет - не знаю) одну мысль (справедливую для одномерных диапазонов) : сортировка простым макросом на листе бьёт всё
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Все зависит от задачи, может нужно смотреть в сторону SQL?
Если есть большой объем данных и нужно только один раз найти значение, то используем обычный перебор. Асимптотика алгоритма O(n) Если нужен многократный поиск, то имеет смысл один раз отсортировать массив, а затем бинарным поиском искать значения. При этом сама сортировка это достаточно затратный способ, чтобы каждый раз перед поиском значений сортировать массив, имеет смысл это сделать только один раз. Асимптотика у "пузырьковой сортировки" O(n^2), у "быстрой сортировки" - O(n * LOG n) (в худшем случае может быть O(n^2)), при этом поиск элементов осуществляется достаточно быстро за O(LOG n)
Встроенный механизм сортировку в самом Excel достаточно быстрый, думаю что любая реализация сортировки средствами VBA будет медленнее.
Михаил, не всё так просто. Есть версия пузырьковой сортировки, называемая "гребешковая", которая вполне себе быстрая Пузырьковая сортировка и все-все-все, хотя расходится с этим исследованием. Свою версию на VBA сравнивал с quick sort на нём же. до 300000 случайных равномерно сгенерированных значений - почти нет разницы. Jack Famous, вы всё же не столь обще описали бы задачу. Так сложно что-то предложить, поскольку рассуждения скатываются к сферическому коню в вакууме Если массив данных большой, то, на мой всгляд, проще хранить в таблице базы Access, создав индекс по полю соединения, и оттуда дёргать требуемые значения запросом. Но опять же, нужно понимать цикл работы для выборки.
Доброго утра! MCH и Андрей VG, спасибо вам большое за подробности и сравнения! Вот это я и называю живым обсуждением и "делиться опытом"
Цитата
Андрей VG написал: не столь обще описали бы задачу
сделал это, повторюсь, чтобы различные варианты послушать, как, например, у вас или MCH. Согласен - довольно размытая постановка вопроса.
Расскажу всю историю (осторожно - простыня):
1. Когда базы огромные, то в Excel им делать нечего. Надо хранить их в специализированных местах и анализировать выборками/фильтрами. 2. Когда таблички небольшие и их мало, то со скоростью работы в целом и с ВПР (и аналогами) в частности также проблем нет — сгодится абсолютно всё. И даже условное форматирование, счётеслимн и суммпроизв не замедлят работу на малых объёмах. 3. А у меня есть промежуточный вариант. Что-то вроде продвинутого калькулятора на словарях в виде отдельных таблиц и таблиц ввода данных, куда подтягиваются данные словаря по ключу (сейчас через VBA-версию ВПР с проверками). Там и условное форматирование есть (подсветка красным пустых ячеек, которые должны быть заполнены) и построчная проверка формулой СЧИТАТЬПУСТОТЫ (также, чтобы всё, что должно быть заполнено не оставалось пустым) и всё в таком духе. И на объектах расчёта (стройка) больше среднего такая база-калькулятор начинает подтормаживать. Ничего супермедленного, но бесит.
Первое, что я сделал — отключил автопересчёт. Это, на удивление, ОЧЕНЬ существенно ускорило ввод данных. Повесил пересчёт на панель быстрого доступа и через пару дней привык на автомате "обновляться". Потом внедрил отключение автопересчёта повсеместно.
Второе — убрал УФ (которое было повсеместно) отовсюду, кроме полей обязательного ввода. Это на 500к ячейках (по всем таблицам, где использовалось) также дало весьма ощутимый прирост.
Вышеперечисленных методов мне хватило надолго, однако базы выросли в объёме. Выросли не от увеличения сложности объекта, а от увеличения подробности базы-калькулятора. Переходить на другие платформы типа Access и SQL, или конкретно настраивать связку через PQ и PP не хочется, потому что в Excel всё такое родное и понятное)))
Поэтому третий этап я начал с переключения многих проверок на макросы. Создаю именованные диапазоны для проверки. Так как они основаны на полях умных таблиц, то являются динамическими — это очень удобно. Сейчас пишу макросы для проверки этих именованных диапазонов. Это также снимет нагрузку и с некоторых УФ, и с формул типа СЧЁТЕСЛИ (проверка на уникальность вводимого ключа). Смысл такой, что человек вводит и не парится, а когда нужно проверить, запускает макрос и он по именованным диапазонам проводит все необходимые проверки и выводит отчёт, всё ли в порядке и, если не всё, то где проблемы.
Так вот логичным продолжением 3го этапа является перенос ВПР'а (и аналогов) также на макросы. Однако, чтобы увидеть картину по объекту нужно "обновиться", то есть пересчитать формулы (или, если ВПР будет на макросах, то запустить макросы). И тут я подумал: а какая на фиг разница — макросом ли у меня подтягиваются значения по ключам или функцией, которая пересчитывается вручную. И вот тут я начал искать способы "ускорить" саму функцию. И нашёл статьи про бинарный поиск))) Получается, последнее, что я смогу улучшить (из того, что знаю и перед тем, как менять методы организации БД и связей между ними) — это написать самые примитивные макросы на сортировку полей моих справочников перед пересчётом и использовать бинарный поиск в ИНДЕКС+ПОИСКПОЗ.
Вопрос: ВПР с ИСТИНОЙ в 4ом параметре и ПОИСКПОЗ с ИСТИНОЙ в 3ем параметре при обеспечении отсортированных данных дадут одинаковый прирост?
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Я бы от другого в данном случае плясал: - есть 500к строк, нужно найти 1 значение (рассчитать формулу ВПР) - здесь без разницы вообще. Никакие макросы не ускорят обычную функцию. Впрочем, MCH об этом и писал. - есть 500к строк, нужно найти 500к значений в справочнике (т.е. ВПР для каждой строки) - вот здесь уже надо по конкретным кейсам:
1) можно ли предварительно отсортировать справочник на листе? 2) если нет - то надо оценить варианты работы макроса: а) копируем лист справочника, штатно сортируем, ВПР-им, если нужно - убиваем копию б) копируем справочник в массив, сортируем массив в памяти, впр-им массив в) копируем справочник в массив, запихиваем его в словарь, достаем из словаря по ключам. г) то же самое с коллекциями д) ничего никуда не копируем, а ВПРим макросом без бинарного поиска маленькими порциями
Вот что-то мне говорит, что варианты в) или г) будут быстрее, чем вариант б) - если я правильно понимаю, запихивание в словарь это O(n), в то время как сортировка всяко больше
Цитата
MCH написал: у "пузырьковой сортировки" O(n^2), у "быстрой сортировки" - O(n * LOG n)
, при сравнимом (наверное, не проверял) времени поиска в словаре и бинарного ВПР.
а вариант а) - тоже любопытно, можно проверить, не быстрее ли на объеме.
Ух круто, Максим!))) Спасибо вам за варианты и советы! Со словарями своя тема: так как это файл-конструктор, то словари, как и сама база, заполняются постепенно пользователем — соответственно, либо пополнять VBAшный словарь новыми данными и удалять из него, если что-то изменилось, либо убивать старый словарь и каждый раз грузить новый. Так как (воп.1) сортировка на листе вполне допустима, то так я, скорее всего, и поступлю, тем паче, что со словарями, массивами и иже с ними мне только ближе к концу года предстоит столкнуться. Буду оптимизировать, пока хватит навыков)))) уже смотрю в сторону Access, SQL и PQ с PP))) последние 2 в любом случае нужны - для аналитики. А пока я PQ использую для связи один-ко-многим (спасибо Андрею) и по-мелочи для причёсывания данных или отображения кросс-таблиц в виде плоских (и наоборот) Максим, кстати, Андрей 2 ссылки дал на обзор методов сортировки и на тест производительности. Обзор мне очень зашёл - там гифки так наглядно принцип работы показывают, что аж загляденье
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Максим Зеленский написал: Вот что-то мне говорит, что варианты в) или г) будут быстрее, чем вариант б) - если я правильно понимаю, запихивание в словарь это O(n), в то время как сортировка всяко больше
Максим, вы забыли учесть, что стоимость вставки в словарь/коллекцию log(n) , если все элементы массива уникальны, так что тоже n * log(n)
webley, рад вас видеть в своей теме! Если не ошибаюсь, то, что вы предлагаете, и есть бинарный поиск с проверкой, описанный тут. ikki (RIP) в сообщении #20 также предлагал ускорить функцию, проверяя через ИНДЕКС, а не ВПР'ом.
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄