Страницы: Пред. 1 2 3 4 5 След.
RSS
Инструменты для работы с массивами в VBA (COM), Фильтр для массива
 
Добавил возможность фильтровать одномерные массивы.
Добавил проверку правильности заполнения параметров.
Выложил описание и релизы библиотек на сайт.
«Бритва Оккама» или «Принцип Калашникова»?
 
bedvit, ты задавал вопрос «Как у тебя будет выглядеть решение, когда нужно посчитать условия по 2ум столбцам: выбрать "машь ивановых" и "петь петровых":
(с1="маша" AND с2="иванова") OR (с1 = "петя" AND с2 = "петров")»
Ответ

Также прикрепляю ответ (только визуализация) на вопрос о реализации сложного условия (от медведя), урезанную версию которого ты выложил
Визуализация

Цитата
bedvit: Теперь условия задаются в удобной форме
Вот это прикол)))
Изменено: Jack Famous - 12.09.2022 13:14:34
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Добавил Like (пока с символом подстановки "*"). Скорость Like оптимизировал до сравнимой с поиском подстроки (содержит подстроку). Быстро.
Прошу тестировать.
Надстройка на сайте
Примеры использования здесь.
«Бритва Оккама» или «Принцип Калашникова»?
 
Маски: "начало строки*", "*конец строки", "строка с пропущенными * или нет данными" — всё ищет?
Изменено: Jack Famous - 21.09.2022 09:34:49
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Да, стандартно все. Ищет и просто "*" (любой текст), и без звездочки (равенство). Применяется для строки.
Изменено: bedvit - 21.09.2022 09:48:10
«Бритва Оккама» или «Принцип Калашникова»?
 
bedvit, ты не ответил на прямо поставленный вопрос.
Переформулирую: Твой Like равносилен по возможностям штатному, если в штатном использовать из спецсимволов только *?
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Выше ответил, что функционал по маске стандартен.
Возможным исключением может являтся поиск по числовым типам данным. У меня только строка. Если нужно, можно числовой массив преобразовать в строковой, и все ОК.
Изменено: bedvit - 21.09.2022 10:11:21
«Бритва Оккама» или «Принцип Калашникова»?
 
Доделал функционал по регистру. Теперь каждое условия является полностью независимым. Т.е. можно по одному и тому же столбцу (или разным столбцам) задать условия LIKE без учета регистра и поиск подстроки с учетом регистра и поиск числа больше 5 и т.д. т.е. любая комбинация условий поддерживается.
Тестовая версия.
Выложил на сайт релиз.
Изменено: bedvit - 23.09.2022 09:12:00
«Бритва Оккама» или «Принцип Калашникова»?
 
Т.е. таким образом можно легко отфильтровать данные, которые отличаются регистром от задаваемых или отделить числа от текста (чисел записанные как текст) и т.д., как в одном столбце, так и в нескольких.
«Бритва Оккама» или «Принцип Калашникова»?
 
Виталий, дорого времени! Попытался с помощью вашей функции смастерить аналог СУММЕСЛИМН, но что-то пошло не так. Тема на Кибере (одна из недавних, не знаю можно ли здесь размещать ссылки). На данном этапе лишь сумел сделать подготовку параметров, но сама функция почему-то не работает ругается на аргументы, хотя вроде бы все верно. В чем может быть загвоздка.
Код
Public arrRes As Variant
'Public bVBA As BedvitCOM.VBA
Public arrV As Variant
Public bvParam() As Variant

Function SUMIFS2(ParamArray argArr() As Variant)
'    Dim bVBA As BedvitCOM.VBA
    Dim i&, n&, clmn&, clmBgn&, clmEnd&, clmnS&(), Ub&, Ub2&
    Dim Rng As Range, Sh As Worksheet
    Ub = UBound(argArr)
    Ub2 = Ub / 2
    ReDim clmnS(0 To Ub2)
    ReDim bvParam(1 To Ub2, 1 To 6)          'массив параметров для функции bVBA.arrayFilterV()
    clmnS(0) = argArr(0).Column               'номер суммируемого столбца
    Set Sh = argArr(0).Worksheet
    n = 1
    For i = 1 To Ub Step 2
          clmnS(n) = argArr(i).Column
          bvParam(n, 1) = 1                     'и
'         bvParam(n, 3) = clmnS(n)              'столбец
          bvParam(n, 4) = 2                     'равно
          bvParam(n, 5) = argArr(i + 1)         'значение
          n = n + 1
    Next
    With WorksheetFunction
        clmBgn = .Min(clmnS)                    'первый столбец диапазона
        clmEnd = .Max(clmnS)                    'последний столбец диапазона
    End With
    For n = 1 To Ub2
          bvParam(n, 3) = clmnS(n) - clmBgn + 1 'столбец (с поправкой на начало диапазона)
    Next
    With Sh.UsedRange
        Set Rng = Range(.Columns(clmBgn), .Columns(clmEnd))
    End With
    arrV = Rng.Value
'    bVBA.ArrayFilterV arrV, bvParam, 0, arrRes
'    ***
    
    SUMIFS2 = bvParam
End Function
Параметры такого вида.
1012BU0
1022Barley0
1042Shipment payment0
1052Арт_Trade0
1062Saransk0
1072railway; RAT0
1092Tariff, rub0
Дополняю: заработало после убирания скобок у bvParam(). Теперь осталось придумать все остальное (завтра) )
Изменено: testuser - 29.09.2022 19:40:40
 
testuser, да ссылку можно приложить, даже нужно. Возможно кто-то тоже заинтересуется таким инструментом. Жду результаты.
«Бритва Оккама» или «Принцип Калашникова»?
 
bedvit, Результаты функция выдает, но немного странные. Оборачивать в UDF наверное не самый лучший вариант, но интересно было проверить такую возможность.. Может быть предложите лучший вариант https://www.cyberforum.ru/vba/thread3024923.html
Изменено: testuser - 30.09.2022 02:14:30
 
По ссылке ошибка 502 Bad Gateway
 
Юрий М, у них там какое-то обслуживание в это время обычно, как я понимаю. Заметил это именно по утрам (по мск ночью). Хотя сейчас ссылка открылась нормально.
 
Цитата
написал:
результаты функция выдает, но немного странные.
Глянул на свежую голову, на самом деле, видимо ни чего странного, нормальный результат - одна строка, видимо такова задумка тамошнего топикстартера. В udf библиотека отказывается работать, проблемма не большая, можно оформить целиком макросом. В udf в т.ч. какие-то проблеммы даже с подготовкой параметров - от руки срабатывает, нажимаю Ctrl - S - кажет ошибку. Еще момент - функция отрабатывает 7 раз прежде чем выдать значение в ячейке. Не знаю с чем связано, по условию 7 столбцов, но всег параметров в 2 раза больше. В общем много непонятной шняги с udf, макрос определенно более лучшее решение.
Изменено: testuser - 30.09.2022 12:08:26
 
По теме: мой фильтр хорошо справляется с большими массивами и небольшим количеством вызовов, желательно сразу все в 1м вызове (затраты на вызов функции из COM, проверка входящих параметров и т.д.).
В качестве составляющей UDF, когда вызовов UDF много - думаю, эффективность будет не высокой.
Но все же UDF написал, тестируйте (см. вложение)
Код
Option Explicit
Dim bCOMvba  As New BedvitCOM.VBA 'раннее связывание

Function SUMIFS2(rngIn As Range, columnSum As Long, column1 As Long, filtr1 As Variant, Optional column2 As Long, Optional filtr2 As Variant, Optional column3 As Long, Optional filtr3 As Variant, Optional column4 As Long, Optional filtr4 As Variant, Optional column5 As Long, Optional filtr5 As Variant, Optional column6 As Long, Optional filtr6 As Variant, Optional column7 As Long, Optional filtr7 As Variant) As Double
    Dim p, arrRes, arrIn, x As Long, c As Long, res As Double ' i As Long, x As Long,
    
    If column1 > 0 Then c = c + 1: If column2 > 0 Then c = c + 1: If column3 > 0 Then c = c + 1: If column4 > 0 Then c = c + 1: If column5 > 0 Then c = c + 1: If column6 > 0 Then c = c + 1: If column7 > 0 Then c = c + 1
    ReDim p(c - 1, 5)
    If column1 > 0 Then p(x, 0) = 1: p(x, 1) = 0: p(x, 2) = column1: p(x, 3) = 2: p(x, 4) = filtr1: p(x, 5) = 0: x = x + 1
    If column2 > 0 Then p(x, 0) = 1: p(x, 1) = 0: p(x, 2) = column2: p(x, 3) = 2: p(x, 4) = filtr2: p(x, 5) = 0: x = x + 1
    If column3 > 0 Then p(x, 0) = 1: p(x, 1) = 0: p(x, 2) = column3: p(x, 3) = 2: p(x, 4) = filtr3: p(x, 5) = 0: x = x + 1
    If column4 > 0 Then p(x, 0) = 1: p(x, 1) = 0: p(x, 2) = column4: p(x, 3) = 2: p(x, 4) = filtr4: p(x, 5) = 0: x = x + 1
    If column5 > 0 Then p(x, 0) = 1: p(x, 1) = 0: p(x, 2) = column5: p(x, 3) = 2: p(x, 4) = filtr5: p(x, 5) = 0: x = x + 1
    If column6 > 0 Then p(x, 0) = 1: p(x, 1) = 0: p(x, 2) = column6: p(x, 3) = 2: p(x, 4) = filtr6: p(x, 5) = 0: x = x + 1
    If column7 > 0 Then p(x, 0) = 1: p(x, 1) = 0: p(x, 2) = column7: p(x, 3) = 2: p(x, 4) = filtr7: p(x, 5) = 0: x = x + 1
    
    arrIn = rngIn
    bCOMvba.ArrayFilterV arrIn, p, 1, arrRes 'применяем фильтр
    
    For x = 1 To UBound(arrRes)
       SUMIFS2 = SUMIFS2 + arrIn(arrRes(x), columnSum)
    Next
End Function
Изменено: bedvit - 30.09.2022 12:16:00
«Бритва Оккама» или «Принцип Калашникова»?
 
Цитата
testuser написал:
В udf библиотека отказывается работать,
всё работает, см. выше.
Цитата
testuser написал:
функция отрабатывает 7 раз прежде чем выдать значение в
значит что-то неправильно делаете. Это вообще не относится к моей библиотеке. Отрабатывает 1 раз как и положенно, см. выше.
Изменено: bedvit - 30.09.2022 12:22:54
«Бритва Оккама» или «Принцип Калашникова»?
 
Цитата
написал:
Это вообще не относится к моей библиотеке
Конечно, это скорее относится к особенностям рабты udf vba на листе при задании параметров (массива) в виде диапазонов. Просто была цель сделать функцию, подобную СУММЕСЛИМН в привычном виде. Может быть роль играют, даже какие-то функции/формулы в этих диапазонах, которые инициируют повторную калькуляцию. Но тем-не менее, я все это хочу обхитрить, не в целях какой-то эффективности, просто некий спортивный интерес. )
 
Цитата
testuser написал:
функцию, подобную СУММЕСЛИМН в привычном виде.
выше это и сделал, в силу специфики задачи, тестируйте.
«Бритва Оккама» или «Принцип Калашникова»?
 
bedvit, привилегия тестирования пока остается за автором вопроса, который к сожалению и как часто бывает ушел в оффлайн. Выражу такое предположение, что эффект (или как это обозвать) лишних итераций функций на листе (за один калькуляционный цикл) касается не тлько udf, написанных на VBA, но и на Visual Studio и стандартных функций в т.ч. И учитывая одну эту особенность, + то что сама по себе функция "тяжелая", работающая с массивом данных, вариант с вашей библитекой мог бы показать лучшее время, если добавить, так скажем "защиту" от лишних пересчетов. К слову, в вашем примере я насчитал 7 лишних пересчетов. В моем последнем варианте было 3. Не знаю от чего это зависит, но 3 - это уже учетверение времени пересчета.
Изменено: testuser - 02.10.2022 11:25:54
 
Что за эффект лишних итераций, лишних пересчетов? О каких 7 лишних пересчетах вы пишите? Не про это ли?
Если да, то это проблема мастера функций, а не функций. Никаких лишних пересчетов нет.
Вывод: не пользуйтесь Мастером функций для отладки пользовательской функции. При обычной вставке функции в ячейку все работает нормально.
Изменено: bedvit - 02.10.2022 14:54:17
«Бритва Оккама» или «Принцип Калашникова»?
 
bedvit, просто добавляю Debug.Print "SUMIFS2" в код функции и Debug.Print "WSCalculate" в событие калькуляции Worksheet_Calculate, захожу в ячейку (одна ячейка, одна функция) - Enter, смотрю.. Про мастер функций читал ваш топик.
Изменено: testuser - 02.10.2022 17:42:01
 
testuser, матчасть по волатильным (пересчитываемым или летучим) функциям в excel
Убираем эти функции (сохраняем в значениях), оп-па Debug.Print "SUMIFS2" показывает 1 итерацию, как и должно быть. Никаких лишних пересчетов.
«Бритва Оккама» или «Принцип Калашникова»?
 
Цитата
bedvit написал:
Убираем эти функции (сохраняем в значениях), оп-па Debug.Print "SUMIFS2" показывает 1 итерацию, как и должно быть. Никаких лишних пересчетов.
Да, замечал, там функция Месяц() или как ее там, и кто его значе какие еще, люди очень любят СМЕЩ, ДВССЫЛ..УФ, но суть это Скверна (!!)
Изменено: testuser - 02.10.2022 18:33:33
 
     Хотел показать, как можно пользователю трансформировать задачу в параметры фильтра. Смысл был в том, чтобы [мысленно или на бумажке] заменить столбцы 3, 4 и 5 двумерного массива параметров на "переменные" а, б и в (как в школе), составить из них выражение и потом уже "развернуть" переменные обратно в параметры массива.
    Но фильтр выдаёт далеко не тот результат, который ожидается. На примере возвращаются только строки "маша" и "саша". Почему не вернулись строки "где маша", "а саша где" и "маша и саша потеряны" — лично мне решительно непонятно.
    Для меня это ещё один аргумент не в пользу инструмента. Если для использования нужен мануал, а мануала нет, то кто его будет использовать…
Скрин
Код

UPD: установка скобок, чтобы получилось "(а и б) или в" ничего не изменила
Код

UPD 2: Не может найти символ переноса строки. Что ещё он не может искать? Какие ограничения? Где они описаны?
Код
Тут мой косяк — нужно * поставить или с параметром 8 (InStr) искать
Изменено: Jack Famous - 05.06.2023 14:29:14
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Цитата
Jack Famous написал:
Но фильтр выдаёт далеко не тот результат, который ожидается. На примере возвращаются только строки "маша" и "саша". Почему не вернулись строки "где маша", "а саша где" и "маша и саша потеряны" — лично мне решительно непонятно.     Для меня это ещё один аргумент не в пользу инструмента. Если для использования нужен мануал, а мануала нет, то кто его будет использовать…
какой мануал тебе нужен? Открой инструкции по LIKE, вот тебе и мануал.

Ты задаешь условия: (с1 Like "маша" And с1 Not Like "ваша") Or с1 Like "саша"
И получаешь правильный ответ:
0            маша
1            саша


Задаеш условия: (с1 Like "*маша*" And с1 Not Like "*ваша*") Or с1 Like "*саша*"
Код
Option Explicit

Sub TestBV()
Dim Bed As New BedvitCOM.VBA
Dim arr, p, n&
 
arr = Array("маша", "саша", "где ваша маша", "где маша", "а саша где", "где все дети", "маша и саша потеряны")
 
ReDim p(1 To 3, 1 To 6)
 
p(1, 1) = 0: p(1, 2) = "(": p(1, 3) = 1: p(1, 4) = 256:       p(1, 5) = "*маша*": p(1, 6) = ""
p(2, 1) = 1: p(2, 2) = "":  p(2, 3) = 1: p(2, 4) = 256 + 512: p(2, 5) = "*ваша*": p(2, 6) = ")"
p(3, 1) = 0: p(3, 2) = "":  p(3, 3) = 1: p(3, 4) = 256:       p(3, 5) = "*саша*": p(3, 6) = ""
 
Bed.ArrayFilterV arr, p, False, arr
 
For n = 0 To UBound(arr)
    Debug.Print n, arr(n)   ' маша, саша
Next n
 
End Sub

Получишь ответ:
0            маша
1            саша
2            где маша
3            а саша где
4            маша и саша потеряны


Что тебе здесь решительно не понятно, как LIKE работает?
В общем, если матчасть не помнишь, это еще один аргумент, открыть и почитать инфо, а не пинать рабочий инструмент.
«Бритва Оккама» или «Принцип Калашникова»?
 
bedvit, признаю, мой косяк. Главное — в примере ниже сразу понял, что не так, а наверх не поднялся  :)
    У логики есть приоритет? A Or B And C можно представить как A + B * C? Или равнозначны?

UPD: на тестовом массиве (16 777 214) из моей темы проверил, насколько передача двух масок Like "0*" и "*0" медленнее передачи одной маски "0*0". Отбор составляет — 4 194 304 строк из указанного массива ~17млн. Разница очень небольшая — 1,5 против 1,3. Это очень хорошо  :idea:
Изменено: Jack Famous - 06.06.2023 10:48:49
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Jack Famous, равнозначны. Думал о приоритетах, но оставил равные. Так надежнее. Есть скобки, если нужно поднять приоритет.
P.S.
Можно, конечно, сделать полный аналог VBA логики, но там у меня появляются сложности в сложных выражениях, когда одна чать Or, другая And, одни в скобках в одних, другие в скобках в начале, конце выражения. Сложно распарсить, можно допустить ошибку. Поэтому, что бы не делать ошибок, беру выражение как есть, выполняю сначала в скобках, а потом просто последовательно по операторам (без приоритета). Если есть желание можем подумать над задачей парсинга всем форумом, я реализую.
Изменено: bedvit - 06.06.2023 10:36:58
«Бритва Оккама» или «Принцип Калашникова»?
 
Цитата
bedvit: равнозначны
это приемлемо. Просто нужно понимать. Всем форумом участия зря ждёшь  :D
     Я по-прежнему считаю, что сравнение условий текстовой строкой было бы намного удобнее и позволило бы убрать 3 столбца из массива параметров, что дополнительно упростило бы ввод. Если это не будет медленнее, то можешь подумать об этом, но, вроде, ты всё уже давно решил.

P.S.: я добавил сравнение в посте выше.
    Нужен конвертор из вариативного в строковый массив (напоминаю). Конвертор в вариативный работает отлично  :idea:
Изменено: Jack Famous - 06.06.2023 10:49:47
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Ты думаешь эта запись

намного удобнее, чем эта

?
У тебя появляется дополнительный параметр сравнение строк, у меня сразу это в массиве параметров прописывается.
Не всегда это экономия 3х столбцов, если нужно простой набор параметров, но к примеру 100 строк, у меня это всего 1 столбец (or/end), сразу с данными, у тебя нужно прописывать вручную строку из 100 переменных. Это удобно пользователю?
Мы с тобой по-моему где то уже проговаривали, что первая (твоя) запись условий не универсальна, какие-то условия в ней нельзя записать.
К примеру, как в твоем варианте прописать простое условие:
(c1 like *маша* or c1=вася) and c1<>маша иванова
?
Изменено: bedvit - 06.06.2023 12:29:53
«Бритва Оккама» или «Принцип Калашникова»?
Страницы: Пред. 1 2 3 4 5 След.
Наверх