Функции сделаны достаточно универсальными без заметной потери в скорости - использование не должно вызвать проблем
ВАЖНО: перед тестированием функций, посмотрите хоть немного, с чем она работает и откуда берёт входящие данные — это всегда диапазон листа и он должен быть заполнен. Не заполнил сам, чтобы не превысить размер файла
Принцип:
• собираем адреса в одномерный массив • сцепляем в одну строку: Join(arr, ",") (очень быстро) • режем по запятой строку адресов на строки длиной максимально близко к 255 символам, но не больше (очень полезная функция) • полученные строки преобразуем в диапазоны и собираем в массив диапазонов — полученный массив диапазонов объединяем с помощью Union, каждый раз забивая его аргументами под завязку (30 диапазонов) (долго и на большом количестве диапазонов и лучше не надо - см. итоги) — на выходе получаем 1 диапазон, с которым делаем, что нужно (в примере это фоновая заливка) • на выходе получаем массив укрупнённых диапазонов и в цикле по нему красим
Модуль «TestDel» (удаление строк)
Код
Option Explicit
Option Private Module
'====================================================================================================
Sub TestDelRows() ' Del 250 000 cells (best: ~ 2.7 sec)
Dim rng As Range
Dim x, arrAdr() As String, arrR() As Range
Dim adr$, t!, tt!, ttt!, r&, i&
ttt = Timer: t = Timer
i = 100000
ReDim arrAdr(i - 1): i = -1
ReDim arrR(UBound(arrAdr))
For r = 1 To (UBound(arrAdr) + 1) * 4 Step 4
' i = i + 1: arrAdr(i) = Rows(r).Address(0, 0, xlA1)
' i = i + 1: Set arrR(i) = Rows(r)
i = i + 1: arrAdr(i) = "C" & r
Next r
Debug.Print "Get Rows:", Format$(Timer - t, "0.00 sec")
t = Timer
arrR = PRDX_AddressToRanges(shDel, Join(arrAdr, ","))
Debug.Print "Get rArray:", Format$(Timer - t, "0.00 sec"), "Blocks:", UBound(arrR) + 1
t = Timer
For Each x In arrR
x.Value2 = 1
Next x
Debug.Print "Crit Insert:", Format$(Timer - t, "0.00 sec")
t = Timer
r = Cells(Rows.Count, 1).End(xlUp).Row
With ActiveSheet.Sort
.SortFields.Add Key:=Range("C1:C" & r), SortOn:=xlSortOnValues, Order:=xlDescending, DataOption:=xlSortNormal
.SetRange Range("A1:C" & r)
.Header = xlNo
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
Debug.Print "Sort:", Format$(Timer - t, "0.00 sec")
t = Timer
Rows("1:" & UBound(arrAdr) + 1).Delete
Debug.Print "Del Rows:", Format$(Timer - t, "0.00 sec")
Debug.Print "Total time:", Format$(Timer - ttt, "0.00 sec")
End Sub
Модуль «TestInt» (заливка ячеек)
Код
Option Explicit
Option Private Module
'====================================================================================================
Sub TestInterrior() ' Test on 187 468 cells, selected from range (best: ~ 3.5 sec)
Dim rng As Range
Dim x, arr, arrR() As Range
Dim adr$, t!, tt!, ttt!, r&
ttt = Timer: t = Timer
Set rng = shInt.UsedRange
rng.Interior.ColorIndex = xlNone
Debug.Print "Prepare:", Format$(Timer - t, "0.00 sec")
t = Timer
adr = GetAddress(rng)
Debug.Print "Get Address:", Format$(Timer - t, "0.00 sec"): Debug.Print String$(100, "=")
' ===== Paint ONE Range block = 8.4 sec (3rd place)
tt = Timer
t = Timer ' Cut Address to Range Array ~ 2.2 sec
arrR = PRDX_AddressToRanges(shInt, adr)
Debug.Print "Get Ranges:", Format$(Timer - t, "0.00 sec")
t = Timer ' Paint ONE Range ~ 6.2 sec
PRDX_UnionArray(arrR).Interior.Color = vbYellow
Debug.Print "Paint Whole:", Format$(Timer - t, "0.00 sec")
Debug.Print "• whole:", Format$(Timer - tt, "0.00 sec"): Debug.Print String$(100, "=")
' ===== END block
' ===== CP cycle block (2.9 sec) = 2.9 sec (1st place)
tt = Timer
t = Timer ' Cut Address to Range Array ~ 2.2
arrR = PRDX_AddressToRanges(shInt, adr)
Debug.Print "Get Ranges:", Format$(Timer - t, "0.00 sec")
t = Timer ' Paint Ranges in Array ~ 0.7 sec
For Each x In arrR
x.Interior.Color = vbYellow
Next x
Debug.Print "Paint Array:", Format$(Timer - t, "0.00 sec")
Debug.Print "• cycle:", Format$(Timer - tt, "0.00 sec")
' ===== END block
t = Timer ' Cut & Paint = 3.17 sec (2nd place)
PRDX_AddressPaint shInt, adr
Debug.Print "• simple:", Format$(Timer - t, "0.00 sec")
Debug.Print "Total time:", Format$(Timer - ttt, "0.00 sec")
End Sub
'====================================================================================================
Function GetAddress(rng As Range) As String
Dim arr, arrOut()
Dim i&, r&, c&
ReDim arrOut(rng.Count - 1)
arr = rng.Value: i = -1
For c = 1 To UBound(arr, 2)
For r = 1 To UBound(arr, 1)
If arr(r, c) < 1500 Then i = i + 1: arrOut(i) = rng(r, c).Address(0, 0, xlA1)
Next r
Next c
Debug.Print "Cells Find:", i + 1
ReDim Preserve arrOut(i): GetAddress = Join(arrOut, ",")
End Function
Модуль «PRDX» (мои функции для работы)
Код
Option Explicit
Option Private Module
'====================================================================================================
Const UnMax& = 30
'====================================================================================================
' Функция принимает лист и строку адресов с этого листа в виде одномерного массива, а возвращает массив "укрупнённых" адресов
' Например передаём массив адресов 1 млн отдельных ячеек (отобрали по какому-либо критерию с листа); это ~6 символов на каждый + 1 млн запятых в разделителях = строка 7 млн символов
' Функция вернёт массив ДИАПАЗОНОВ примерно в ~ 27,5 тыс штук (7 млн / 255 символов)
' Красить в цикле 1 миллион диапазонов/ячеек или 27,5 тысяч - это разница в десятки и сотни раз по времени (например, 1 секунда вместо 2ух минут)
' Скорость резки на строковых функциях просто фантастическая - 3 секунды на 200 тыс адресов отдельных ячеек
' Union при таком количестве диапазонов нам не помощник. Даже максимально эффективная его версия. Можно считать "резку строки" своеобразным супер-Union'ом
Function PRDX_AddressToRanges(sh As Worksheet, ByVal txAdr$) As Range()
Dim arrRanges() As Range, r&, i&
Const maxLen& = 255
'Const maxLen& = 50 ' тестировал резку на блоки разной длины
If InStr(txAdr, "$") Then txAdr = Replace$(txAdr, "$", "")
i = Len(txAdr)
If i < maxLen + 1 Then
ReDim arrRanges(0): Set arrRanges(0) = sh.Range(txAdr)
PRDX_AddressToRanges = arrRanges: Exit Function
End If
r = -1: ReDim arrRanges(i \ (maxLen \ 2)) ' создаём массив для хранения с запасом
Do
i = InStrRev(Left$(txAdr, maxLen), ",") ' ищем запятую с конца первых 255 символов взятой строки
r = r + 1: Set arrRanges(r) = sh.Range(Left$(txAdr, i - 1)) ' заполняем массив диапазонов
txAdr = Mid$(txAdr, i + 1) ' отрезаем от адресной строки использованный фрагмент (взятая строка)
If Len(txAdr) < maxLen + 1 Then ' если остаток строки можно сразу преобразовать в диапазон, то заканчиваем и выходим
r = r + 1: Set arrRanges(r) = sh.Range(Left$(txAdr, i - 1))
ReDim Preserve arrRanges(r): PRDX_AddressToRanges = arrRanges
Exit Function
End If
Loop
End Function
'----------------------------------------------------------------------------------------------------
' Процедура для закрашивания диапазонов сразу при резке строки (просто для примера и теста скорости)
Sub PRDX_AddressPaint(sh As Worksheet, ByVal txAdr$)
Dim i&
If InStr(txAdr, "$") Then txAdr = Replace$(txAdr, "$", "")
i = Len(txAdr): If i < 256 Then sh.Range(txAdr).Interior.Color = vbYellow: Exit Sub
Do
i = InStrRev(Left$(txAdr, 255), ",")
sh.Range(Left$(txAdr, i - 1)).Interior.Color = vbYellow
txAdr = Mid$(txAdr, i + 1)
If Len(txAdr) < 256 Then sh.Range(txAdr).Interior.Color = vbYellow: Exit Sub
Loop
End Sub
'====================================================================================================
'====================================================================================================
' Функция объединяет все диапазоны переданного массива в один диапазон, который и возвращает
Function PRDX_UnionArray(arrRng() As Range) As Range
Dim i&, j&, n&
Do
j = -1
For i = 0 To UBound(arrRng) Step UnMax
j = j + 1
Set arrRng(j) = PRDX_UnionSmart(arrRng, i)
Next i
ReDim Preserve arrRng(j)
If j < UnMax Then Set PRDX_UnionArray = PRDX_UnionSmart(arrRng): Exit Function
Loop
End Function
'----------------------------------------------------------------------------------------------------
' Функция для "умного" объединения диапазонов из переданного массива с помощью Union
' Основной смысл — объединять по 30 диапазонов за раз (максимум для Union). Реже вызов Union = выше скорость
' Функция получает массив диапазонов и индекс элемента, с которого нужно начать объединения (первый элемент массива с индексом 0 - по умолчанию)
' Функция постарается максимально "забить" Union всеми 30ю аргументами-диапазонами, а, если их меньше, то всеми оставшимися
Function PRDX_UnionSmart(arrRng() As Range, Optional iStart&) As Range
Dim s&, n&
s = iStart
n = UBound(arrRng) - s + 1 ' количество элементов от стартового и до конца массива
If n > UnMax Then n = UnMax
If n = UnMax Then Set PRDX_UnionSmart = Union(arrRng(s), arrRng(s + 1), arrRng(s + 2), arrRng(s + 3), arrRng(s + 4), arrRng(s + 5), arrRng(s + 6), arrRng(s + 7), arrRng(s + 8), arrRng(s + 9), arrRng(s + 10), arrRng(s + 11), arrRng(s + 12), arrRng(s + 13), arrRng(s + 14), arrRng(s + 15), arrRng(s + 16), arrRng(s + 17), arrRng(s + 18), arrRng(s + 19), arrRng(s + 20), arrRng(s + 21), arrRng(s + 22), arrRng(s + 23), arrRng(s + 24), arrRng(s + 25), arrRng(s + 26), arrRng(s + 27), arrRng(s + 28), arrRng(s + 29)): Exit Function
If n < 14 Then
If n = 1 Then Set PRDX_UnionSmart = arrRng(s): Exit Function
If n = 2 Then Set PRDX_UnionSmart = Union(arrRng(s), arrRng(s + 1)): Exit Function
If n = 3 Then Set PRDX_UnionSmart = Union(arrRng(s), arrRng(s + 1), arrRng(s + 2)): Exit Function
If n = 4 Then Set PRDX_UnionSmart = Union(arrRng(s), arrRng(s + 1), arrRng(s + 2), arrRng(s + 3)): Exit Function
If n = 5 Then Set PRDX_UnionSmart = Union(arrRng(s), arrRng(s + 1), arrRng(s + 2), arrRng(s + 3), arrRng(s + 4)): Exit Function
If n = 6 Then Set PRDX_UnionSmart = Union(arrRng(s), arrRng(s + 1), arrRng(s + 2), arrRng(s + 3), arrRng(s + 4), arrRng(s + 5)): Exit Function
If n = 7 Then Set PRDX_UnionSmart = Union(arrRng(s), arrRng(s + 1), arrRng(s + 2), arrRng(s + 3), arrRng(s + 4), arrRng(s + 5), arrRng(s + 6)): Exit Function
If n = 8 Then Set PRDX_UnionSmart = Union(arrRng(s), arrRng(s + 1), arrRng(s + 2), arrRng(s + 3), arrRng(s + 4), arrRng(s + 5), arrRng(s + 6), arrRng(s + 7)): Exit Function
If n = 9 Then Set PRDX_UnionSmart = Union(arrRng(s), arrRng(s + 1), arrRng(s + 2), arrRng(s + 3), arrRng(s + 4), arrRng(s + 5), arrRng(s + 6), arrRng(s + 7), arrRng(s + 8)): Exit Function
If n = 10 Then Set PRDX_UnionSmart = Union(arrRng(s), arrRng(s + 1), arrRng(s + 2), arrRng(s + 3), arrRng(s + 4), arrRng(s + 5), arrRng(s + 6), arrRng(s + 7), arrRng(s + 8), arrRng(s + 9)): Exit Function
If n = 11 Then Set PRDX_UnionSmart = Union(arrRng(s), arrRng(s + 1), arrRng(s + 2), arrRng(s + 3), arrRng(s + 4), arrRng(s + 5), arrRng(s + 6), arrRng(s + 7), arrRng(s + 8), arrRng(s + 9), arrRng(s + 10)): Exit Function
If n = 12 Then Set PRDX_UnionSmart = Union(arrRng(s), arrRng(s + 1), arrRng(s + 2), arrRng(s + 3), arrRng(s + 4), arrRng(s + 5), arrRng(s + 6), arrRng(s + 7), arrRng(s + 8), arrRng(s + 9), arrRng(s + 10), arrRng(s + 11)): Exit Function
If n = 13 Then Set PRDX_UnionSmart = Union(arrRng(s), arrRng(s + 1), arrRng(s + 2), arrRng(s + 3), arrRng(s + 4), arrRng(s + 5), arrRng(s + 6), arrRng(s + 7), arrRng(s + 8), arrRng(s + 9), arrRng(s + 10), arrRng(s + 11), arrRng(s + 12)): Exit Function
Else
If n = 14 Then Set PRDX_UnionSmart = Union(arrRng(s), arrRng(s + 1), arrRng(s + 2), arrRng(s + 3), arrRng(s + 4), arrRng(s + 5), arrRng(s + 6), arrRng(s + 7), arrRng(s + 8), arrRng(s + 9), arrRng(s + 10), arrRng(s + 11), arrRng(s + 12), arrRng(s + 13)): Exit Function
If n = 15 Then Set PRDX_UnionSmart = Union(arrRng(s), arrRng(s + 1), arrRng(s + 2), arrRng(s + 3), arrRng(s + 4), arrRng(s + 5), arrRng(s + 6), arrRng(s + 7), arrRng(s + 8), arrRng(s + 9), arrRng(s + 10), arrRng(s + 11), arrRng(s + 12), arrRng(s + 13), arrRng(s + 14)): Exit Function
If n = 16 Then Set PRDX_UnionSmart = Union(arrRng(s), arrRng(s + 1), arrRng(s + 2), arrRng(s + 3), arrRng(s + 4), arrRng(s + 5), arrRng(s + 6), arrRng(s + 7), arrRng(s + 8), arrRng(s + 9), arrRng(s + 10), arrRng(s + 11), arrRng(s + 12), arrRng(s + 13), arrRng(s + 14), arrRng(s + 15)): Exit Function
If n = 17 Then Set PRDX_UnionSmart = Union(arrRng(s), arrRng(s + 1), arrRng(s + 2), arrRng(s + 3), arrRng(s + 4), arrRng(s + 5), arrRng(s + 6), arrRng(s + 7), arrRng(s + 8), arrRng(s + 9), arrRng(s + 10), arrRng(s + 11), arrRng(s + 12), arrRng(s + 13), arrRng(s + 14), arrRng(s + 15), arrRng(s + 16)): Exit Function
If n = 18 Then Set PRDX_UnionSmart = Union(arrRng(s), arrRng(s + 1), arrRng(s + 2), arrRng(s + 3), arrRng(s + 4), arrRng(s + 5), arrRng(s + 6), arrRng(s + 7), arrRng(s + 8), arrRng(s + 9), arrRng(s + 10), arrRng(s + 11), arrRng(s + 12), arrRng(s + 13), arrRng(s + 14), arrRng(s + 15), arrRng(s + 16), arrRng(s + 17)): Exit Function
If n = 19 Then Set PRDX_UnionSmart = Union(arrRng(s), arrRng(s + 1), arrRng(s + 2), arrRng(s + 3), arrRng(s + 4), arrRng(s + 5), arrRng(s + 6), arrRng(s + 7), arrRng(s + 8), arrRng(s + 9), arrRng(s + 10), arrRng(s + 11), arrRng(s + 12), arrRng(s + 13), arrRng(s + 14), arrRng(s + 15), arrRng(s + 16), arrRng(s + 17), arrRng(s + 18)): Exit Function
If n = 20 Then Set PRDX_UnionSmart = Union(arrRng(s), arrRng(s + 1), arrRng(s + 2), arrRng(s + 3), arrRng(s + 4), arrRng(s + 5), arrRng(s + 6), arrRng(s + 7), arrRng(s + 8), arrRng(s + 9), arrRng(s + 10), arrRng(s + 11), arrRng(s + 12), arrRng(s + 13), arrRng(s + 14), arrRng(s + 15), arrRng(s + 16), arrRng(s + 17), arrRng(s + 18), arrRng(s + 19)): Exit Function
If n = 21 Then Set PRDX_UnionSmart = Union(arrRng(s), arrRng(s + 1), arrRng(s + 2), arrRng(s + 3), arrRng(s + 4), arrRng(s + 5), arrRng(s + 6), arrRng(s + 7), arrRng(s + 8), arrRng(s + 9), arrRng(s + 10), arrRng(s + 11), arrRng(s + 12), arrRng(s + 13), arrRng(s + 14), arrRng(s + 15), arrRng(s + 16), arrRng(s + 17), arrRng(s + 18), arrRng(s + 19), arrRng(s + 20)): Exit Function
If n = 22 Then Set PRDX_UnionSmart = Union(arrRng(s), arrRng(s + 1), arrRng(s + 2), arrRng(s + 3), arrRng(s + 4), arrRng(s + 5), arrRng(s + 6), arrRng(s + 7), arrRng(s + 8), arrRng(s + 9), arrRng(s + 10), arrRng(s + 11), arrRng(s + 12), arrRng(s + 13), arrRng(s + 14), arrRng(s + 15), arrRng(s + 16), arrRng(s + 17), arrRng(s + 18), arrRng(s + 19), arrRng(s + 20), arrRng(s + 21)): Exit Function
If n = 23 Then Set PRDX_UnionSmart = Union(arrRng(s), arrRng(s + 1), arrRng(s + 2), arrRng(s + 3), arrRng(s + 4), arrRng(s + 5), arrRng(s + 6), arrRng(s + 7), arrRng(s + 8), arrRng(s + 9), arrRng(s + 10), arrRng(s + 11), arrRng(s + 12), arrRng(s + 13), arrRng(s + 14), arrRng(s + 15), arrRng(s + 16), arrRng(s + 17), arrRng(s + 18), arrRng(s + 19), arrRng(s + 20), arrRng(s + 21), arrRng(s + 22)): Exit Function
If n = 24 Then Set PRDX_UnionSmart = Union(arrRng(s), arrRng(s + 1), arrRng(s + 2), arrRng(s + 3), arrRng(s + 4), arrRng(s + 5), arrRng(s + 6), arrRng(s + 7), arrRng(s + 8), arrRng(s + 9), arrRng(s + 10), arrRng(s + 11), arrRng(s + 12), arrRng(s + 13), arrRng(s + 14), arrRng(s + 15), arrRng(s + 16), arrRng(s + 17), arrRng(s + 18), arrRng(s + 19), arrRng(s + 20), arrRng(s + 21), arrRng(s + 22), arrRng(s + 23)): Exit Function
If n = 25 Then Set PRDX_UnionSmart = Union(arrRng(s), arrRng(s + 1), arrRng(s + 2), arrRng(s + 3), arrRng(s + 4), arrRng(s + 5), arrRng(s + 6), arrRng(s + 7), arrRng(s + 8), arrRng(s + 9), arrRng(s + 10), arrRng(s + 11), arrRng(s + 12), arrRng(s + 13), arrRng(s + 14), arrRng(s + 15), arrRng(s + 16), arrRng(s + 17), arrRng(s + 18), arrRng(s + 19), arrRng(s + 20), arrRng(s + 21), arrRng(s + 22), arrRng(s + 23), arrRng(s + 24)): Exit Function
If n = 26 Then Set PRDX_UnionSmart = Union(arrRng(s), arrRng(s + 1), arrRng(s + 2), arrRng(s + 3), arrRng(s + 4), arrRng(s + 5), arrRng(s + 6), arrRng(s + 7), arrRng(s + 8), arrRng(s + 9), arrRng(s + 10), arrRng(s + 11), arrRng(s + 12), arrRng(s + 13), arrRng(s + 14), arrRng(s + 15), arrRng(s + 16), arrRng(s + 17), arrRng(s + 18), arrRng(s + 19), arrRng(s + 20), arrRng(s + 21), arrRng(s + 22), arrRng(s + 23), arrRng(s + 24), arrRng(s + 25)): Exit Function
If n = 27 Then Set PRDX_UnionSmart = Union(arrRng(s), arrRng(s + 1), arrRng(s + 2), arrRng(s + 3), arrRng(s + 4), arrRng(s + 5), arrRng(s + 6), arrRng(s + 7), arrRng(s + 8), arrRng(s + 9), arrRng(s + 10), arrRng(s + 11), arrRng(s + 12), arrRng(s + 13), arrRng(s + 14), arrRng(s + 15), arrRng(s + 16), arrRng(s + 17), arrRng(s + 18), arrRng(s + 19), arrRng(s + 20), arrRng(s + 21), arrRng(s + 22), arrRng(s + 23), arrRng(s + 24), arrRng(s + 25), arrRng(s + 26)): Exit Function
If n = 28 Then Set PRDX_UnionSmart = Union(arrRng(s), arrRng(s + 1), arrRng(s + 2), arrRng(s + 3), arrRng(s + 4), arrRng(s + 5), arrRng(s + 6), arrRng(s + 7), arrRng(s + 8), arrRng(s + 9), arrRng(s + 10), arrRng(s + 11), arrRng(s + 12), arrRng(s + 13), arrRng(s + 14), arrRng(s + 15), arrRng(s + 16), arrRng(s + 17), arrRng(s + 18), arrRng(s + 19), arrRng(s + 20), arrRng(s + 21), arrRng(s + 22), arrRng(s + 23), arrRng(s + 24), arrRng(s + 25), arrRng(s + 26), arrRng(s + 27)): Exit Function
If n = 29 Then Set PRDX_UnionSmart = Union(arrRng(s), arrRng(s + 1), arrRng(s + 2), arrRng(s + 3), arrRng(s + 4), arrRng(s + 5), arrRng(s + 6), arrRng(s + 7), arrRng(s + 8), arrRng(s + 9), arrRng(s + 10), arrRng(s + 11), arrRng(s + 12), arrRng(s + 13), arrRng(s + 14), arrRng(s + 15), arrRng(s + 16), arrRng(s + 17), arrRng(s + 18), arrRng(s + 19), arrRng(s + 20), arrRng(s + 21), arrRng(s + 22), arrRng(s + 23), arrRng(s + 24), arrRng(s + 25), arrRng(s + 26), arrRng(s + 27), arrRng(s + 28)): Exit Function
End If
MsgBox "UNcorrect ranges!", vbCritical, "UnionSmart"
Err.Raise xlErrNA
End Function
'====================================================================================================
'====================================================================================================
Предлагаю новое название для темы: «Диапазоны (Ranges). Как быстро отобрать области и/или удалить строки по критериям»
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Во время разработки космической программы, NASA столкнулась с проблемой: обыкновенные шариковые ручки не пишут в невесомости. И тогда агентство привлекло лучших учёных страны, и потратило несколько миллионов долларов налогоплательщиков для того, чтоб разработать специальную "космическую ручку". Это чудо техники могло писать в невесомости и вакууме, на жаре и на морозе, и вообще являлось лучшей ручкой времён и народов. А советское руководство тем временем снабдило своих космонавтов простыми и дешёвыми карандашами.
bedvit: уже третья тема на Range.Address, может просто нужно в первой все обосновать?
первая про то, как получить адрес диапазона, состоящего из множества областей (и её превратили в помойку - отдельное "спасибо"), вторая - в Курилке и про обсуждение "зачем", нежели про конкретные способы. Эта же тема — с готовыми решениями: "Бери и пользуйся", как говорит Николай Владимирович
что-то мне подсказывает, что сразу использовать твои "наработки" в своих проектах не получиться (один Union Union'ов чего стоит) - всё равно надо писать функции и процедуры — у меня всё уже написано и это ДАЛЕКО не тоже самое, что у тебя (вообще подходы похожи только понимаем того, что Union нужно забивать под завязку), не говоря уже про шуструю "резку строк" (у тебя строка адреса "заполняется под завязку" в процессе отбора, что неудобно для работы с другими процедурами)
и пустил по миру очередную тему А если серьёзно — где твой "карандаш"? Наверное предложишь глазками искать, да ручками выделять Я уже 3ю тему жду, а ты до сих пор не можешь понять, зачем собирать адреса и никаких альтернатив не предлагаешь…
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Я не могу предложить альтернативное решение применение которого мне не понятно. Я ж писал на полном серьезе. Метод ради метода - не поддерживаю. С областью по крайним точкам в первой теме разобрались - простое решение. Даже если оно окажется медленным, то предпочту 4 строки. Леш приведи пример реального использования на примере 2-3 областей. Заметь, я не критикую само решение, я применимость к чему либо невкуриваю.
это потому, что ты сделал свой подход на основании моего (только еще парсинг строки добавил.), а я свой сделал на основании алгоритма от ZVI. Не разобрал как тестировать твой код, думаю и по скорости из-за парсинга прогрывает.
БМВ: Я не могу предложить альтернативное решение применение которого мне не понятно
и что же тебе непонятно в этом примере "закрасить ячейки с двоечками"?
Цитата
БМВ: Даже если оно окажется медленным, то предпочту 4 строки
о - ну так у нас тогда разные задачи, т.к. я VBA деньги зарабатываю и все мои инструменты должны быть максимально быстрыми (особенно, если брать разницу в десятки-сотни раз, как тут)
это просто смешно — я взял оттуда только забивку Union под завязку и, заметь, совершенно другая функция, то есть "взял" по факту просто понимание того, что Union нужно применять с 30ю диапазонами, потому что он медленный. Без твоего кода, сделал бы это "открытие" несколькими минутами/часами позднее при тестировании, т.к. и так было понятно, кто "тормоз"
Цитата
bedvit: думаю и по скорости из-за парсинга прогрывает
время "парсинга" собранных адресов с распилом на блоки и получением диапазонов составляет 0,02 секунды на 25 тысячах отдельных ячеек/адресов. Время сбора адресов должно быть меньше твоего, т.к. у тебя дополнительные проверки на длину стэка. То есть при +- одинаковом времени сбора, я трачу ЦЕЛЫХ ДВЕ СОТЫХ секунды на то, чтобы превратить переданный массив адресов в диапазоны максимально длинных адресов
Повторюсь, используя данный подход, я могу из любой процедуры насобирать массивы по критериям и ПРОСТО ПЕРЕДАТЬ ИХ, безо всяких контролей стэков и прочего
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Это все слова, в моем алгоритме, по ссылке (см.выше) от 2016 года, обработка 250 тыс. ячеек с выделением 60 тыс.-5сек. Какое у тебя время? Прикладывай пример, померяемся....
у тебя вылизанный код для одной единственной задачи, а у меня 3 функции для применения в любых условиях (на входе одномерный массив адресов, на выходе 1 диапазон) — и какой смысл в сравнении? Ради интереса можно, конечно - сколько времени у тебя займёт получение диапазона (объект Range) из 25 тыс ячеек примера (каждая 4я ячейка, из диапазона "A2:A100000")?
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
If k > 256 Then If j + 1 > 30 Then i = i + 1: j = 1: k = L + 1 Else j = j + 1: k = L + 1 ' При переполнении текущего буфера
If k = L + 1 Then s(i, j) = addr Else s(i, j) = s(i, j) & "," & addr 'первый без запятой
а чего ты вообще весь код в 1 строку не засунул - всех бы победил навсегда
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Тестовый стенд есть в той теме, которую я скинул выше. Вот он
Код
Sub заполнить_лист()
Dim i&, j&, t#, a&(1 To 10000, 1 To 25)
t = Timer
For i = 1 To 10000
For j = 1 To 25
a(i, j) = Int(Rnd * 2000)
Next
Next
[a1].Resize(10000, 25) = a
Debug.Print Timer - t
End Sub
Задача: выделить в полученном стенде - вся ячейки , значением более 1500
bedvit, хорошие новости - ты выиграл 0,1 сек (спишу для себя на вывод Debug'ов) лол
Скрины
обновил СС
Отдельно прошу обратить внимание, насколько маленькая мне понадобилась процедура для теста (фактически, преобразование массива адресов в 1 диапазон занимает всего 1 строку) — всё делают функции, просто передай им адреса Вот так стараешься-стараешься, а потом гораздо более удобный универсальный код твоему не проигрывает
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Вопрос-то не в том, что я выиграл на 0,1 сек., я это и ранее знал, что будет быстрее. Вопрос в том, что еще 4 марта, в твоей первой теме я тебе сказал, что парсить строку более 255 символов, дольше, чем сразу обрабатывать. Вот ответ к твоей первой теме (можно было там и продолжить, а не делать 3 штуки).
bedvit: Вопрос в том, что еще 4 марта, в твоей первой теме я тебе сказал, что парсить строку более 255 символов, дольше, чем сразу обрабатывать
не мешки ворочать, как говориться - никаких сравнений ты не делал, да и сейчас это пустые слова, т.к. макрос состоит не только из сбора адресов с распилом — с одной стороны и сбора строк с контролем длины каждой — в другом. Нет так ли? Там ты сказал, что это бред, однако разницы с твоим "комбайном" по скорости по сути НЕТ. Ты даже стесняешься это признать, т.к. не ожидал - не так ли?)))
Можно проверить вчистую, но теперь давай-ка уже сам - сам палец о палец не ударил. Мне в любом случае, контроль каждой строки при сборе — не нужен, потому что это неудобно. Если даже ты прав и вся разница в скорости это проигрыш "распила", то я готов "подождать" 0,1 сек в пользу гораздо большего удобства работы Как бы тебе пришлось поменять своего монстрилу, чтобы "влезть" в мой пример? А в другой? То-то же — у меня это заняло пару минут
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
БМВ, больше удивлён, что через расширенный делал, а не через обычный Что насчёт отбора по данным Витали или нескольких групп диапазонов по типу ColorMap или отбора значений по условию больше/меньше, по маске? Как сработает там? Если искать в умных таблицах? Для наших с Виталей вариантов это не проблема, а вот расширенный фильтр, думаю, тут не поможет Я бы сказал, что вариант отличный, но только для конкретного примера — не очень универсальный способ, зато, безусловно, быстрый (тут вопросов нет — добавлю в СС)
Уделывает (0,3 сек у дядь Миши против 2 у меня на 25 тыс выбранных)
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Алексей, в борьбе за универсальность мы получаем продукты раздутые и не оптимальные. Говноприложение на телефоне занимающее 100мб - это норма... зачем оптимизировать, лучше сказать что нужен телефон с большим объемом памяти .,....
Расширенный - да просто чтоб автофильтр не включать и не отключать :-). Да и делал то только для того чтоб показать что цель достигается другими средствами, хотя всегда может оказаться что фильтр установлен пользователем и решение его сбросит......
БМВ: зачем оптимизировать, лучше сказать что нужен телефон с большим объемом памяти
а ты с другой стороны посмотри — зачем "усираться" (платить более крутому программеру, например, или тратить больше времени) в борьбе за уменьшение размера на 20, скажем Мб (1/5 от общего размера твоего примера), если 1 фотка на современном телефоне "весит" 5 Мб??? Я, например, понимаю, разрабов: нет нескольких мегабайт на обновление, так используй старые приложения или не используй вообще и считай на калькуляторе - так и энергию сэкономишь
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
БМВ написал: Расширенный - да просто чтоб автофильтр не включать и не отключать
не скажи. Тут есть и более грубокий смысл. В расширенном фильтре фильтровать даты(а так же отформатированные форматом числа) значительно удобнее. Плюс можно навороченные формулы использовать для отбора. Так что есть причины использовать его в определенных случаях. Ну а меньше-больше, подстановка и прочее и в автофильтре доступны. А вот цвет - тут без авто или доп. столбцов не обойтись.
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
Дмитрий, это для конкретного случая. я было хотел сперва в F2 загнать =R2С1=2 и оставить пустым F1 но потом оставил как есть. А так - инструмент очень мощьный.
он ещё и строки длиннее 255 символов фильтрует - я его как раз для этого в основном использую. Насчёт дат, времени и прочего - действительно намного проще, чем штатный вот только "посмотреть" фильтр в отличие от штатного нельзя. Если бы не этот минус, то про штатный в VBA бы забыл Но это всё оффтоп - что насчёт использования его для отбора в диапазоне нескольких столбцов без шапки, как в примере у Витали?
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Option Explicit
'====================================================================================================
Dim arrAdr(), fArr As Boolean
'====================================================================================================
Sub Tester()
Dim rng As Range
Dim adr$, t!, a&, r&, c&
fArr = True
'fArr = False
t = Timer
TestByBedVit
If fArr Then
Set rng = ArrayUnion(arrAdr)
Else
Set rng = AddressToRange(shBedVit, Join(arrAdr, ","))
End If
Debug.Print Format$(1000 * (Timer - t), "0 ms"), rng.Count
End Sub
' Count: 62 402 cells
' MyStack: 6.8 sec
' BedVit: 6.95 sec
' MyAddress: 7 sec
'====================================================================================================
Sub TestByBedVit()
Dim rng As Range
Dim x, arr, tmp() As String
Dim adr$, a&, r&, c&, i&, l&, ll&, flag As Boolean
Set rng = shBedVit.Range("A1:Y10000")
arr = rng.Value: a = -1: i = -1
r = UBound(arr, 1) * UBound(arr, 2)
If fArr Then
ReDim tmp(99)
ReDim arrAdr(r \ 10)
Else
ReDim arrAdr(r - 1)
End If
For c = 1 To UBound(arr, 2)
For r = 1 To UBound(arr, 1)
If arr(r, c) > 1500 Then
adr = rng(r, c).Address(0, 0)
If fArr Then
l = Len(adr) + 1
ll = ll + l
If ll > 253 Then ' если в стэке строка длиннее 253 символов (с запятыми)
If ll < 257 Then ' если получается строка длиной 254, 255 или 256 символов, то текущий адрес является последним для стэка
flag = True
i = i + 1: tmp(i) = adr
End If
ReDim Preserve tmp(i)
a = a + 1: Set arrAdr(a) = shBedVit.Range(Join(tmp, ","))
ReDim tmp(99)
If flag Then ' если флаг был выставлен, то текущий адреc влез, иначе поместить первым в новый стэк
flag = False: i = -1: ll = 0
Else
i = 0: tmp(0) = adr: ll = l
End If
Else
i = i + 1: tmp(i) = adr
End If
Else
a = a + 1: arrAdr(a) = adr
End If
End If
Next r
Next c
If i <> -1 Then ' если в стэке что-то осталось, то добавляем
ReDim Preserve tmp(i)
a = a + 1: Set arrAdr(a) = shBedVit.Range(Join(tmp, ","))
End If
ReDim Preserve arrAdr(a)
End Sub
'====================================================================================================
мой вариант чуть быстрее (0,15 сек при том, что это не 1 макрос, а передача параметров), чем у bedvit'а, но всё равно в пределах погрешности Чуда не случилось - коль значимого выигрыша стэк (компоновка максимально длинных для создания адреса строк) не даёт, а проблем и неудобств больше (во всяком случае — для меня)
Выводы: • Повторюсь (bedvit также на это указывает), что резка одной огромной строки или компоновка в цикле (без разницы) — это всё ~ 1% от всего времени работы, а значит нет смысла что-то докручивать в этой части алгоритма. Основное время съедает Union — надо что-то ещё покрутить с ним… • Расширенный фильтр Есть сомнения, что лидерство сохранится при увеличении количества отобранных диапазонов и/или столбцов для поиска В любом случае, специфика работы этого инструмента не позволяет его использовать настолько же свободно, как решения, не привязанные к инструментам Excel
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Однажды Лебедь, Рак да Щука Везти с поклажей воз взялись, И вместе трое все в него впряглись; Из кожи лезут вон, а возу всё нет ходу! Поклажа бы для них казалась и легка: Да Лебедь рвется в облака, Рак пятится назад, а Щука тянет в воду. Кто виноват из них, кто прав, – судить не нам; Да только воз и ныне там
ничего подобного — воз по всей поляне летает, припарковать не можем
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄