Страницы: 1 2 3 4 5 След.
RSS
Инструменты для работы с массивами в VBA (COM), Фильтр для массива
 
Моё почтение, джентльмены!
Готов инструмент фильтрации массива с любым количеством столбцов, по любым условиям.
ArrayFilterV(VARIANT* array_in, VARIANT* array_parameters, VARIANT_BOOL array_out_index, VARIANT* array_out)
1. array_in - массив входящий (одномерный, двухмерный)
2. array_parameters - массив задаваемых параметров (6 параметров для любого столбца, можно для одного и того же, можно для разных). Количество условий не ограничено. Можно создать самому из списка, можно создать двухмерный массив и заполнить, можно забрать сразу с листа Excel.
3. array_out_index - режим вывода: 0- отфильтрованный массив, 1-массив индексов
4. array_out - массив результатов

Условия в массиве параметров применяются в том же порядке, что и везде. Приоритет скобки, потом "И" и "ИЛИ" (одинаковый приоритет, выполняются в порядке следования)
Параметры массива условий (сделал максимально просто для пользователя):
1-логические операторы (0-ИЛИ, 1-И)
2-скобка открывающая
3-столбец для фильтрации
4-операторы сравнения (//1-меньше, 2-равно, 4-больше, 8-содержит подстроку, 16-резерв(регулярки), 32- игнорировать регистр, 64-резерв(basic),  128-резерв(extended), 256 - LIKE (пока с символом подстановки "*"), 512-НЕ)
5-значение для фильтра
6-скобка закрывающая,

Условия можно задавать как простые:
'фильтр по первому столбцу, значение = 9
Array(, , 1, Равно, 9, "")


так и более сложные, к примеру выше
Array(, "(((", 1, Содержит, "маша", , ИЛИ, , 1, Содержит, "вася", ")", И, , 1, НеРавно, "маша иванова", ")", ИЛИ, "(", 2, НеРавно, "'1", , ИЛИ, , 2, Равно, 1, "))", И, "(", 3, БольшеРавно, 12.5, , И, , 3, МеньшеРавно, 55.8, ")")
или в таком виде (как удобнее)
Array( _
, "(((", 1, Содержит, "маша", , _
ИЛИ, , 1, Содержит, "вася", ")", _
И, , 1, НеРавно, "маша иванова", ")", _
ИЛИ, "(", 2, НеРавно, "'1", , _
ИЛИ, , 2, Равно, 1, "))", _
И, "(", 3, БольшеРавно, 12.5, , _
И, , 3, МеньшеРавно, 55.8, ")" _
)


ArrayFilterV поиск по 10млн. строк с найденными 5 млн. - 4 сек.
В улучшенном варианте (1 этап оптимизации) - 1,76 сек.
Оптимизированный вариант: вывод отфильтрованного массива 5 млн строк (изначальный 10 млн) = 0,25 секунд
вывод массива индексов 5 млн строк (изначальный 10 млн)  = 0,17 секунд


Простой пример (с замером скорости на 10 млн строк) и сложный (с выводом условий и результата):
Код
Option Explicit
'операторы (aliases) псевдонимы
Const ИЛИ = 0, И = 1, РАВНО = 2, СОДЕРЖИТ = 8, НЕРАВНО = 512 + 2, МЕНЬШЕРАВНО = 1 + 2, БОЛЬШЕРАВНО = 4 + 2, МЕНЬШЕ = 1, БОЛЬШЕ = 4

'ОДНОМЕРНЫЙ МАССИВ, ПРОСТЫЕ УСЛОВИЯ
Sub TestArrayFilterV_1()
    'Dim bVBA As New BedvitCOM.VBA 'раннее связывание
    Dim bVBA As Object: Set bVBA = CreateObject("BedvitCOM.VBA") 'позднее связывание
    Dim arrResult
    'первоначальный массив данных
    Dim arrV: arrV = Array(1, 0, 1, 0, 1, 0)
    'массив условий (фильтр по первому столбцу, значение = 1)
    Dim p: p = Array(, , 1, РАВНО, 1, "")

    ' фильтруем ===============================
    bVBA.ArrayFilterV arrV, p, 0, arrResult
    '========================================
    Debug.Print UBound(arrResult) + 1 'начало с 0
End Sub



'ДВУХМЕРНЫЙ МАССИВ, ПРОСТЫЕ УСЛОВИЯ
Sub TestArrayFilterV_2()
    'Dim bVBA As New BedvitCOM.VBA 'раннее связывание
    Dim bVBA As Object: Set bVBA = CreateObject("BedvitCOM.VBA") 'позднее связывание
    Dim arrResult, r, c, t, x
    Dim sizeRow As Long: sizeRow = 10000000
    Dim sizeCol As Long: sizeCol = 1
    Dim arrV: ReDim arrV(1 To sizeRow, 1 To sizeCol) 'первоначальный массив данных, далее хаполняем рендомно
    
    'массив условий (фильтр по первому столбцу, значение = 1)
    Dim p: p = Array(, , 1, РАВНО, 1, "")
    
    'заполняем первоначальный массив с данными
    For r = 1 To sizeRow
        For c = 1 To sizeCol
        arrV(r, c) = CLng(Rnd * 2)
        Next
    Next
    
    t = Timer
    ' фильтруем ===============================
    bVBA.ArrayFilterV arrV, p, 0, arrResult
    '========================================
    Debug.Print Timer - t
    Debug.Print UBound(arrResult) + 1 'начало с 0
End Sub



'ДВУХМЕРНЫЙ МАССИВ, СЛОЖНЫЕ УСЛОВИЯ
Sub TestArrayFilterV_3()

Dim arrParam, arrTest, arrRes, bCOMvba As Object: Set bCOMvba = CreateObject("BedvitCOM.VBA")

Cells.ClearContents

'создаем тестовый массив
arrTest = Array("маша иванова", "'1", 13, "маша иванова", 1, 13, "маша", "'1", 14, "вася", "'1", 14, "паша", 1, 50, "вася", 2, 52, "маша", 1, 60, "вася", 1, 65)
bCOMvba.Array1Dto2D arrTest, 1, 1, UBound(arrTest) / 3: bCOMvba.Transpose arrTest
Cells(1, 1).Resize(UBound(arrTest, 1), UBound(arrTest, 2)) = arrTest

'запись условий для фильтра:(((c1 like "маша" or like "вася") and c1<>"маша иванова") or (c2<>"1" or c2=1)) and (c3>=12,5 and c3<=55,8)
arrParam = Array(, "(((", 1, СОДЕРЖИТ, "маша", , ИЛИ, , 1, СОДЕРЖИТ, "вася", ")", И, , 1, НЕРАВНО, "маша иванова", ")", ИЛИ, "(", 2, НЕРАВНО, "'1", , ИЛИ, , 2, РАВНО, 1, "))", И, "(", 3, БОЛЬШЕРАВНО, 12.5, , И, , 3, МЕНЬШЕРАВНО, 55.8, ")")
'ИЛИ ТАК
arrParam = Array( _
, "(((", 1, СОДЕРЖИТ, "маша", , _
ИЛИ, , 1, СОДЕРЖИТ, "вася", ")", _
И, , 1, НЕРАВНО, "маша иванова", ")", _
ИЛИ, "(", 2, НЕРАВНО, "'1", , _
ИЛИ, , 2, РАВНО, 1, "))", _
И, "(", 3, БОЛЬШЕРАВНО, 12.5, , _
И, , 3, МЕНЬШЕРАВНО, 55.8, ")" _
)
bCOMvba.Array1Dto2D arrParam, 1, 1, UBound(arrParam) / 6: bCOMvba.Transpose arrParam
Cells(1, 5).Resize(UBound(arrParam, 1), UBound(arrParam, 2)) = arrParam

'применяем фильтр
bCOMvba.ArrayFilterV arrTest, arrParam, 0, arrRes
Cells(1, 12).Resize(UBound(arrRes, 1), UBound(arrRes, 2)) = arrRes

End Sub



Выложил описание и релизы библиотек на сайт.
Изменено: bedvit - 21.09.2022 11:24:11
«Бритва Оккама» или «Принцип Калашникова»?
 
Добавлены дополнительные условия фильтрации: 1-меньше, 2-равно, 4-больше, 8-содержит подстроку, 128-НЕ (можно смешивать, к примеру 8+128 - НЕ содержит подстроку)
Добавлен вывод отфильтрованного массива.

Инструмент готов к использованию! Тестируйте.
Пример и файл по ссылке в топике обновил

Список параметров (думаю это будет входящий массив) с условиями фильтрации для каждого столбца и дальнейшая оптимизация (думаю уже сильно не прибавить) будут позже.
.
Изменено: bedvit - 25.08.2022 23:35:07
«Бритва Оккама» или «Принцип Калашникова»?
 
Оптимизированный вариант:
вывод отфильтрованного массива 5 млн строк (изначальный 10 млн) = 0,25 секунд
вывод массива индексов 5 млн строк (изначальный 10 млн)  = 0,17 секунд
«Бритва Оккама» или «Принцип Калашникова»?
 
bedvit, впечатляющее время работы  :idea:
Сделал вариант на VBA — хотел бы видеть всё то же, но на порядки быстрее у тебя в библе  :D

Цитата
bedvit: Добавлены дополнительные условия фильтрации: 1-меньше, 2-равно, 4-больше
думаю, что это должна быть отдельная функция, т.к. у неё свой набор параметров и он никак не вяжется с регистром и равно/не равно — общими для всех типов текстовых поисков (у меня).
Изменено: Jack Famous - 26.08.2022 17:40:35
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Цитата
написал:
bedvit , впечатляющее время работы
Полностью согласен. Но где брать и как подключить этот самый вышеупомянутый BedvitCOM.VBA?
 
Добавил игнорирование регистра:
compare_1- режим сравнения(compare): 1-меньше, 2-равно, 4-больше, 8-содержит подстроку,  64-игнорировать регистр,  128-НЕ (можно смешивать, к примеру 8+64+128 -не содержит подстроку и игнорировать регистр)
Библиотеку обновил по ссылке в топе
Изменено: bedvit - 26.08.2022 20:15:23
«Бритва Оккама» или «Принцип Калашникова»?
 
tolikt,
Цитата
bedvit написал:
Тестовую версию библиотеки можно скачать  здесь  (релиз выложу на  сайте )
просто, качаете xll, открываете или добавляете в папку надстроек/подключаете,что бы само открывалось, пишите код vba и получаете результат, все просто:)
«Бритва Оккама» или «Принцип Калашникова»?
 
bedvit, нужно ещё добавить массив столбцов для фильтрации, массив критериев для каждого и массив параметров. Плюс маска и регулярки
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Ты же не хотел ругулярки?) С масками тоже не все просто. Что такое маска? Какое-то правило обработки строки? Массив критериев - да надо сделать. Это следующее улучшение функционала инструмента.
«Бритва Оккама» или «Принцип Калашникова»?
 
bedvit, лишними не будут)
Маска - это метод Like в VBA. Подобного метода нет в сях? Если нет, то нужен свой аналог - для начала хватит только поддержки *.
Изменено: Jack Famous - 27.08.2022 15:23:02
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
По сути Like это и есть содержит подстроку.
«Бритва Оккама» или «Принцип Калашникова»?
 
bedvit, да что ты говоришь)
Ну почитай про положение звёздочек, знаки вопроса, символы в квадратных скобках и восклицательный знак первым символом в них...
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Добавил возможность задавать любые условия для любого столбца или для гескольких сразу - задавая массив условий.
Приоритет логических операций "и", "или" в порядке следования условий
Параметры:
   '1-логическое or или and (0,1), применяется к последнему результату предыдущего условия.
   '2-номер столбца к которому применяются условия
   '3-входящее условие для фильтра или строка для регулярки
   '4-режим фильтрации: 1-меньше, 2-равно, 4-больше, 8-содержит подстроку, 16-строка содержит нуль терминатор(в след.версии), 32-исользовать регулярки(в след.версии), 64-игнорировать регистр, 128-НЕ
   '5-грамматика регулярного выражения
Регулярные выражения будут добавлены в след. версии.
Это сложный и медленный инструмент, пока неясна его нкобходимость, при текущем уровне задавать неограниченный условия для фильтра.

Библиотеку и пример обновил.
Задаваемое количество условий не ограниченно.
Изменено: bedvit - 29.08.2022 09:39:43
«Бритва Оккама» или «Принцип Калашникова»?
 
bedvit, про Or/And непонятно, режим фильтрации можно сделать проще (не заставлять пользователя запоминать волшебные числа) ну или добавить штатное описание/подсказки к процедуре
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Jack Famous, ты прочитал сообщения 13 и топика? Описание и прииеры смотрел/выполнял?
«Бритва Оккама» или «Принцип Калашникова»?
 
bedvit, прочитал, смотрел, но не выполнял… А что мне даст выполнение в плане понимания?
Если без выполнения непонятно, то это уже тревожный звоночек  :)
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Приложи усилия прочитай внимательно, сделай тест. Я сделал максимально просто и понятно. Задаем массив условий (5 параметров для каждого столбца, так же как и в функции ранее было, только не для одного столбца можно задавать, а для разных, вот и все) .Если что останется непонятного, пиши, что конкренно, отвечу подробнее.
«Бритва Оккама» или «Принцип Калашникова»?
 
Цитата
bedvit: Приложи усилия прочитай внимательно
несколько раз прочёл
Цитата
bedvit: сделай тест
не вижу смысла, пока не понимаю, что делаю
Цитата
bedvit: Я сделал максимально просто и понятно
вообще не согласен  :D

Для начала, расшифруй словами, как ты фильтруешь массив из примера. Добавь строки - у тебя одни цифры пока что…
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Давай так, составь нужный тебе простой пример, и я выложу код его фильтрации.
«Бритва Оккама» или «Принцип Калашникова»?
 
bedvit, второй столбец = "маша", 4ый <>"игорь"
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
arrP(1, 1) = 0: arrP(1, 2) = 2: arrP(1, 3) = "маша": arrP(1, 4) = 2: arrP(1, 5) = 0 '1е условие
   arrP(2, 1) = 1: arrP(2, 2) = 4: arrP(2, 3) = "игорь": arrP(2, 4) = 2+128: arrP(2, 5) = 0 '2е условие
«Бритва Оккама» или «Принцип Калашникова»?
 
Цитата
bedvit:arrP(1, 1) = 0: arrP(1, 2) = 2: arrP(1, 3) = "маша": arrP(1, 4) = 2: arrP(1, 5) = 0 '1е условие
arrP(2, 1) = 1: arrP(2, 2) = 4: arrP(2, 3) = "игорь": arrP(2, 4) = 2+128: arrP(2, 5) = 0 '2е условие
по-твоему, это просто?
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Относительно просто, т.к. это позволяет задать любые условия одним мезанизмом, одним набором параметров.
Стандартный find по диапазону намного лучше?
Можно не указывать последний аргумент в нашем случае
arrP(1, 1) = 0: arrP(1, 2) = 2: arrP(1, 3) = "маша": arrP(1, 4) = 2 '1е условие
  arrP(2, 1) = 1: arrP(2, 2) = 4: arrP(2, 3) = "игорь": arrP(2, 4) = 2+128 '2е условие
«Бритва Оккама» или «Принцип Калашникова»?
 
Можешь назвать массив короче, выйдет так(сути это не меняет)
p(1, 1) = 0: p(1, 2) = 2: p(1, 3) = "маша": p(1, 4) = 2 '1е условие
p(2, 1) = 1: p(2, 2) = 4: p(2, 3) = "игорь": p(2, 4) = 2+128 '2е условие

Готов сравнить по лаконичности с твоим вариантом.
«Бритва Оккама» или «Принцип Калашникова»?
 
bedvit, необходимость условия Or сомнительна, зато пользователю сложнее. Плюс, как я понимаю, это условие работает ограниченно
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Все работает полнофункционально. Возьми наконец и потестируй.
«Бритва Оккама» или «Принцип Калашникова»?
 
bedvit, как будет выглядеть фильтр двухмерного массива, в котором значение в столбце №…:
    • …1 равно "маша" или равно "вася"
    • …2 не равно "игорь" или равно "юля"
    • …3 больше или равно 12,5 и меньше или равно 55,8
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Отношение между столбцами "и" или "или"?
«Бритва Оккама» или «Принцип Калашникова»?
 
bedvit, у меня в примере и/или внутри столбца. Так нельзя?
1ый или 3ий - выбираем, что подошло. 2ой дофильтровывает.
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Внутри столбца я понял, какая логика между столбцами "и" или "или"?
«Бритва Оккама» или «Принцип Калашникова»?
Страницы: 1 2 3 4 5 След.
Наверх