Выбрать дату в календареВыбрать дату в календаре

Страницы: 1 2 След.
Удалить строки содержащие указанные слова
 
Итак, чтобы удалить строки из Excel, есть несколько способов, которые мне известны:
  1. Грубое удаление через Rows().Delete! (Подходит для небольших таблиц с данными);
  2. Сортировка массива + удаление одной операцией (Быстрее, но всё же медленно на больших объёмах, т.к. сортировка это также затратная операция);
  3. Через удаление дубликатов (Реализован ниже);
Скорее всего есть ещё множество вариантов, но если кто шарит, тот предложит!

Теперь сам код и файл для теста:
Скрытый текст

Точные данные по времени выполнения не замеряла, но всё выполняется на уровне кликов (120000 строк) (не более 1 сек.)

В файле кнопочки нажимать в порядке нумерации):
Изменено: AN - 06.10.2023 12:30:23
Удалить строки содержащие указанные слова
 
Jack Famous, здравствуйте. Да просто много Анастасий на форуме, решила сократить для удобства и мне так лучше)

Цитата
написал:
как-то очень много (и не сказать, чтобы очень быстро) для простой простановки критериев для удаления…
Было слово "быстро", но не было "очень быстро"😁!
Код хорошо себя будет показывать при большом количестве критериев для удаления. Опять же, в данном маленьком примере, который привёл realmen80, полный перебор будет немного быстрее себя показывать, т.к. данных немного! Но Вы можете предложить более быструю альтернативу, если имеется!
Цитата
написал:
И самого удаления (как самой затратной операции по времени) нет.
Возможно realmen80, уже не нужен данный код, поэтому не стала заморачиваться) Да и способов быстрого удаления не так уж и много! Также если выполнять алгоритм удаления строк в большой таблице на слабом или даже на средничковом компе, то никакой алгоритм быстро не вывезет!
Цитата
написал:
Удаляем лишние пробелы
Согласна, духота по делу, но всё же, как работает Trim уж думаю рассказывать никому не нужно!
Trim$("  при ме  р           ") = "при ме  р"

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


БМВ, здравствуйте. Опять же всё зависит от входных данных. Например поиск в массиве на 100 элементов в некоторых источниках рекомендуют производить полным перебором (без связки Сортировка + Бинарный поиск), т.к. вычислительной мощности в современном мире хватает для решения данной задачи. В моём примере я сделала код с "запасом", т.к. мне неизвестно количество критериев для удаления и количество совпадений, только количество строк (100 000), но конечно, полный перебор никто не отменял и всегда есть и будут моменты, где он будет предпочтительней усложнённых алгоритмов. Просто таких моментов меньше!
Изменено: AN - 06.10.2023 06:30:04
Удалить строки содержащие указанные слова
 
Sanja, могу согласится, но всё же новичку будет более понятен мой код, т.к. всё декомпозировано, разбито и не в одном цикле!
Удалить строки содержащие указанные слова
 
Sanja, добрый день. Это называется "Валидация входных данных" и цель была предоставить более-менее понятный код, поэтому я его закомментировала!
Плюс по производительности разницы не будет, если Вы об этом!
Удалить строки содержащие указанные слова
 
realmen80, алгоритм на VBA для быстрого детекта (определения) нужных строк для удаления (для удобства всё закомментировала):

Скрытый текст

Если тема для Вас актуальна, то в свободное время слеплю алгоритм для удаления строк!
Изменено: AN - 05.10.2023 15:17:53
Тесты. Как быстро закрасить ячейки, AddressCut / AddressToMaxRanges. Функция для резки одного длинного адреса на блоки максимальной длины (~ 255 символов) с преобразованием в диапазоны
 
Цитата
написал:
ну, непосредственно к теме этот пункт как раз отношения не имеет, т.к. это подготовительный этап.
Ну как это? Это же валидация входных данных, как это отношения не имеет? Без неё алгоритм бесполезен и это является частью алгоритма!

Цитата
написал:
с помощью функций (в конце) из  этой моей темы .
Вся тема заточена под определение столбца, разве в ней присутствует подобное решение (сбор необходимых диапазонов строк)? Столбцы заранее же известны в вашем случае! Вы задаёте диапазон прямо в коде!
Код
arr(i) = Cells(r, 1).Resize(1, 10).Address(0, 0, xlA1)
Цитата
написал:
Им можно давать имена, если что, чтобы понимать, что они скрывают  
Чтобы понять, что они скрывают, их необходимо раскрыть 😎. А информация об спойлере описана прямо над ним!  
Тесты. Как быстро закрасить ячейки, AddressCut / AddressToMaxRanges. Функция для резки одного длинного адреса на блоки максимальной длины (~ 255 символов) с преобразованием в диапазоны
 
Jack Famous, bedvit, приветствую.

Предложу решения по ускорению кода на VBA (с xll соперничать нету смысла и некорректно), но для начала немного декомпозиции:

Алгоритм можно разделить на 3 пункта (рассматривала решение Jack Famous - Time total: 3,270 sec):
  1. Получение адресов нужных ячеек и формирование одномерного массива;
  2. Формирование единой строки с адресами (через Join);
  3. Блочная закраска нужных диапазонов.
Цитата
Важно: Данное решение и так достаточно хорошо отрабатывает, тем более данная операция в большинстве случаев будет требоваться максимум 1 раз! Поэтому ниже представленная оптимизация, по факту не требуется, и представлена чисто с целью предоставить альтернативное решение!

Предложение по оптимизации 1 пункта (Результат 0,3, взамен 1,6):
Скрытый текст


2 пункт и 3 пункт без оптимизации (P.S. К успеху шла, но не получилось, не фартануло!):
Скрытый текст

Итог: Шалость удалась только с пунктом №1 (Итоговое время упало до 2,023)! В остальных случаях оптимизация не имеет смысла, т.к. Jack Famous, уже, на мой взгляд, выжал максимум + идёт упор на объектную модель, где программисты на VBA особой власти не имеют (остается только перебирать реализованные методы Microsoft или пользовательские надстройки и библиотеки на сторонних языках, если основная цель - это максимальная производительность в вычислениях).

Jack Famous, FILE_RangesFromAddress 👍
Изменено: Aнaстaсия - 25.09.2023 10:39:51
Быстрое определения вхождения символа в список, Fast method to Define symbol by List
 
Jack Famous, Приветствую.

Цитата
написал:
Есть у меня ещё интересное исследование по вопросу быстрого форматирования диапазонов
Сейчас просмотрела, очень много всего и так поняла, что эта тема является финальной) А в сообщении #12 последний и актуальный код по сравнению только на чистом VBA?
Если да, то добавлю сегодня свой комментарий!

А что касается решений на Си. Это отлично, но с VBA сравнивать некорректно, так как процесс транслирования кода отличается (в случаи с Си или другим подобным языком, мы пользуемся заранее скомпилированным решением, а VBA хардкориться в RealTime (режиме реального времени), исключая промежуточную компиляцию в подобие байт-кода)! Но Вы Jack Famous, такого же мнения, как Я поняла :) , поэтому поздравляю, у Вас единомышленники!
VBA Как сделать чтобы макрос активировал на каждом листе определенную ячейку
 
eonka, добрый день, самый простой вариант, это активировать нужный лист, затем выделить ячейку:
Код
Sub Example()
    Dim Sh
    For Each Sh In ActiveWorkbook.Worksheets
            Sh.Cells(1, 2) = "123"
            Sh.Cells(1, 4) = "321"
            Sh.Activate ' Добавлено
            Cells(4, 1).Select
    Next Sh
End Sub
Быстрое определения вхождения символа в список, Fast method to Define symbol by List
 
Цитата
написал:
для удаления 1го символа есть отдельная функция в шапке темы. Обойти её вряд ли удастся.
Результат точно такой же String_DelLR_AscW_OneSym, как и в случае String_DelLR_AscW и от 100 символов в строке, преимущество за String_DelLR_InStr_Anastasia т.к. уже начинается разрыв в пользу InStr!

Скрытый текст


Цитата
написал:
2 символа я тестил и мой метод, как минимум, не медленнее, а в ряде случаев быстрее
Тут возможно есть зависимость от железа и Вашему более новому/старому процессору в тандеме с ОЗУ по какой-то причине легче обработать алгоритм с массивом, нежели через InStr c Mid$! В любом случае, я копировала результаты с Immediate Window и обманывать мне нету смысла! А в каких ряде случаев при тесте на 2 символах метод String_DelLR_AscW шустрее?

Цитата
написал:
К тому же есть ещё пространство для ускорения,
Это неплохо, будет интересно просмотреть! А то мельком пробежалась по форуму и особо интересных тем нету. То бесконечные просьбы помощи в коде, то узконаправленные решения, которые мне либо не интересны, либо я в них просто не шарю)
Быстрое определения вхождения символа в список, Fast method to Define symbol by List
 
Jack Famous, благодарю за гайд, до встречи!
Быстрое определения вхождения символа в список, Fast method to Define symbol by List
 
Jack Famous, приветствую!

Цитата
написал:
вы тестили не тот
Поняла и протестила с изменённым методом (удаление 1-2 символов слева/справо):
Код
Len = 10 
            'String_DelLR_AscW s, s2, aL, aR, True, True                    ' 0.4 | 0.5
            'String_DelLR_InStr_Anastasia s, s2, sList, sList, True, True   ' 0.4 | 0.5
Код
Len = 100 
            'String_DelLR_AscW s, s2, aL, aR, True, True                    ' 0.5 | 0.5
            'String_DelLR_InStr_Anastasia s, s2, sList, sList, True, True   ' 0.4 | 0.5
Код
Len = 1000 
            'String_DelLR_AscW s, s2, aL, aR, True, True                    ' 0.5 | 0.6
            'String_DelLR_InStr_Anastasia s, s2, sList, sList, True, True   ' 0.4 | 0.6
Код
Len = 5000 
            'String_DelLR_AscW s, s2, aL, aR, True, True                    ' 0.8 | 0.8
            'String_DelLR_InStr_Anastasia s, s2, sList, sList, True, True   ' 0.5 | 0.6
Код
Len = 10000 
            'String_DelLR_AscW s, s2, aL, aR, True, True                    ' 1.4 | 1.4
            'String_DelLR_InStr_Anastasia s, s2, sList, sList, True, True   ' 0.6 | 0.8
Код
Len = 32767
            'String_DelLR_AscW s, s2, aL, aR, True, True                    ' 4.2 | 4.3
            'String_DelLR_InStr_Anastasia s, s2, sList, sList, True, True   ' 1.9 | 2.1
Алгоритм стал работать быстрее и в некоторых случаях оба алгоритма сравнялись, но обойти алгоритм InStr с Mid$ не удаётся (при sList$ = "./")!

Также результаты тестирования с sList$ = ".,/|\:-" (7 символов)
Код
Len = 10 
            'String_DelLR_AscW s, s2, aL, aR, True, True                     ' 0.8
            'String_DelLR_InStr_Anastasia s, s2, sList, sList, True, True    ' 1.3
Код
Len = 100 
            'String_DelLR_AscW s, s2, aL, aR, True, True                     ' 0.8
            'String_DelLR_InStr_Anastasia s, s2, sList, sList, True, True    ' 1.3
Код
Len = 1000 
            'String_DelLR_AscW s, s2, aL, aR, True, True                     ' 0.9
            'String_DelLR_InStr_Anastasia s, s2, sList, sList, True, True    ' 1.4
Код
Len = 5000 
            'String_DelLR_AscW s, s2, aL, aR, True, True                     ' 1.2
            'String_DelLR_InStr_Anastasia s, s2, sList, sList, True, True    ' 1.5
Код
Len = 10000 
            'String_DelLR_AscW s, s2, aL, aR, True, True                     ' 1.8
            'String_DelLR_InStr_Anastasia s, s2, sList, sList, True, True    ' 1.6
Код
Len = 32767 
            'String_DelLR_AscW s, s2, aL, aR, True, True                     ' 4.7
            'String_DelLR_InStr_Anastasia s, s2, sList, sList, True, True    ' 2.9

Промежуточный итог таков, что алгоритмы неоднозначные и всё зависит от входных данных и поставленных задач:
  1. Если задача состоит в том, чтобы удалить 1-2 символа в начале или конце строки, то метод String_DelLR_InStr, основанный на Mid$ самый лучший вариант, независимо от длины строк #39!
  2. Если задача состоит в том, чтобы удалить >2 символов, то тут можно использовать метод String_DelLR_AscW, но с оговорками, т.к. если обрабатываемые строки небольшие, (<9000) тогда метод в небольшом выигрыше, если нет, то в проигрыше!
Занимая нейтральную позицию, без предвзятости, от себя я бы рекомендовала использовать String_DelLR_InStr! Код небольшой, интуитивно понятный и в тестах особо не уступает и бывает даже лучше отрабатывает! Плюс многим логика String_DelLR_AscW может быть не понятной (я например не сразу допёрла, в чём подвох)!
Быстрое определения вхождения символа в список, Fast method to Define symbol by List
 
БМВ, приношу извинения, думаю это отвлечение от темы было последним, т.к. по последним сообщениям Jack Famous, думаю узнал всё, что ему хотелось об новичке на форуме!
Как правильно формировать строку в цикле, (+ Обсуждение замены Join)
 
Jack Famous, приветствую! Тема старая, но я также задавалась вопросом по замене или оптимизации Join, т.к. есть особенности и ограничения у данного метода! От себя добавлю, и Вам тоже думаю будет интересно:
Цитата
написал:
Есть еще одна интересная тема - байтовое представление текста. Эта штука работает очень быстро.
Согласна быстро, но не достаточно и идея неплохая, но данный способ не учитывает само время преобразования из строки в байты! А вышеперечисленные алгоритмы напрямую работают со строками и лишены этой операции! А чем длиннее строки, тем дольше будет осуществляется это преобразовании строки в байт-массив! Как итог: не всегда работа с байтами быстрее работы с данными на прямую, это касается высокоуровневый кодов!

Мы имеем 3 алгоритма:
Код
Sub ConcatFast()
Dim temp(), x, tm!, i&, j&, v$, line$
If Not GetArray(temp) Then Exit Sub Else tm = Timer: line = " "
    For Each x In temp
        v = x & ";": j = i + Len(v)
        If j > Len(line) Then line = line & Space$(Len(line))
        Mid$(line, i + 1) = v: i = j
    Next x
line = Left$(line, j - 1)
Debug.Print "ConcatFast (Time): " & Format$(Timer - tm, "0.000 ms")
Debug.Print "ConcatFast (Len): " & Len(line)
End Sub
Код
Sub ConcatJoin()
Dim arrNum(), temp(), x, tm!, n&, line$
If Not GetArray(temp) Then Exit Sub Else tm = Timer: ReDim arrNum(0 To (UBound(temp, 1) * UBound(temp, 2) - 1)): n = -1
    For Each x In temp
        n = n + 1: arrNum(n) = x
    Next x
line = Join(arrNum, ";")
Debug.Print "ConcatJoin (Time): " & Format$(Timer - tm, "0.000 ms")
Debug.Print "ConcatJoin (Len): " & Len(line)
End Sub
Код
Function aJoin(arr(), del)
Dim a&, b&
For a = LBound(arr) To UBound(arr): b = b + Len(arr(a)): Next
aJoin = Space$(b + (UBound(arr) - LBound(arr)) * Len(del)): b = 1
    For a = LBound(arr) To UBound(arr)
        Mid$(aJoin, b, Len(arr(a))) = arr(a): b = b + Len(arr(a))
        If a <> UBound(arr) Then Mid$(aJoin, b, Len(del)) = del: b = b + Len(del)
    Next a
End Function

Комментарий по ConcatFast: Всё хорошо и спасибо за данное сконструированное решение, но есть один недочёт, а именно:
Код
If j > Len(line) Then line = line & Space$(Len(line))
У вас в тестах Вы формируете массив из единиц:
Код
Function GetArray(arr()) As Boolean
Dim c&, r&: ReDim arr(1 To 1000000, 1 To 100)
    For c = 1 To UBound(arr, 2)
        For r = 1 To UBound(arr, 1)
            arr(r, c) = 1 ' Я про это!
        Next r
    Next c
GetArray = True
End Function
К сожалению, в большинстве случаев таких данных практически не бывает (Len = 1), поэтому, если Вы увеличите длину тестируемых данных хотя-бы на 1 (Len = 2), то Вы получите некорректные данные на начальном этапе, на выводе:
Код
Function GetArray(arr()) As Boolean
Dim c&, r&: ReDim arr(1 To 1000000, 1 To 100)
    For c = 1 To UBound(arr, 2)
        For r = 1 To UBound(arr, 1)
            arr(r, c) = 1 & "T"
        Next r
    Next c
GetArray = True
End Function
Вывод:
Код
"1T 1  1T 1T;1T;1T;1T;1T;1T;1T...

Это потому, что начальная длина пустой строки, которая впоследствии наращивается имеет начальную длину в один пробел:
Код
line = " "
И при первой же итерации Вам нужно вставить 3 символа ("1T" + разделитель ";"), но строка формируется только на 2 символа:
Код
line = line & Space$(Len(line)) ' line = "  "
И уже при первой итерации, взамен "1T;" мы получаем "1T". Далее данные постепенно нормализуются, но если вставить данные с длиной > 2, например 3 (1TS),то Вы словите ошибку, т.к. метод Mid$ будет вынужден обращаться к несуществующему индексу, ведь длина наращиваемой строки будет меньше, чем требуется!

В общем это духота и не каждый поймет, что я имела ввиду, т.к. это специфичная тема и сложно объяснить простым языком (ещё бы уметь это делать) поэтому предлагаю решения по исправлению данного бага и забыть об этом недочёте)

Чтобы исправить данный баг, предлагаю два решения:
  1. На начальном этапе взять длину строки с запасом, чтобы длина line = " " была гарантированно больше первого элемента просматриваемого массива, далее данные нормализуются. Например у Вас первый элемент имеет длину в 12 символов (x(0) = "Hello_Nig..."), значит line = Space(Len(x) * 2). Но для этого необходимо прописывать дополнительный алгоритм на определение длины первого элемента... Поэтому 2 оптимальный, на мой взгляд, вариант;
  2. Внести изменение в строчку и добавить следующее:
    Код
    До:    If j > Len(line) Then line = line & Space$(Len(line))
    После: If j > Len(line) Then line = line & Space$(Len(line) + Len(x))
    

Всё очень просто и таким образом Вы не особо теряете в производительности (где-то данное решение будет показывать даже лучший результат, всё зависит от данных), и гарантированно получаете корректные данные на выходе, так как наращивание происходит всегда с запасом!

Далее ConcatJoin. Сам Join стандартными методами VBA обогнать не удастся! Microsoft постарались и сделали одну из шустрых функций на VBA:
Цитата
написал:
line = Join(arrNum, ";")
Поэтому решающее значение будут иметь входные данные и скорость их преобразования в одномерный массив:
Цитата
написал:
   For Each x In temp
       n = n + 1: arrNum(n) = x
   Next x
Как итог: ConcatJoin самый оптимальный и простой вариант, т.к. в большинстве случаев Вы не будете работать с Big Data через Excel, посредством VBA!


И aJoin. Что-то мне подсказывает, что Anchoret, шарит и увлекался компилируемыми языками, ведь данное решение, на мой взгляд, отлично себя покажет именно в компилируемом варианте (вычислить общую длину получаемой строки, единожды выделить память под данную строку и заполнить её через цикл, без лишнего изменения и обращения к менеджеру памяти OS, с просьбой выдать ещё свободного места😊). Но хочу указать на то, что это только моё предположение и я могу ошибаться!

Что по данному варианту на VBA, то мы имеем современный интерпретируемый вариант реализации языка (компиляция в промежуточное представление (подобие байт-кода) и выполнение на "виртуальной машине" Excel) и в данном случае это решение будет показывать себя с лучшей стороны, только при очень больших массивах данных, т.к. мы тратим наше "драгоценное" время на подсчёт общей длины строки и используем метод Mid$ два раза, взамен одного в методе ConcatFast. Но в методе ConcatFast мы имеем конкатенацию "line & Space$(Len(line))" и чем больше входных данных, тем медленнее будет отрабатывать данный алгоритм, а aJoin наоборот будет улучшать результат по отношению к ConcatFast!

Итог: Берите ConcatJoin и не парьтесь)

Цитата
Укажу на то, что это старая статья (2019 год) и никаких претензий я не Высказываю (на момент публикации я вообще не имела никаких дел с программированием😁)! Только поделилась своими мыслями и указала на недочёт в алгоритме! Буду признательна аргументированной критике в мой адрес, если это имеет место быть!
Изменено: Aнaстaсия - 25.09.2023 05:53:00
Быстрое определения вхождения символа в список, Fast method to Define symbol by List
 
Но мы отвлеклись от темы...
Многое написано и в принципе всё разобрано на достаточном уровне, поэтому предлагаю Вам Jack Famous, сделать вывод и подвести черту по поводу данной темы, т.к. последнее решение хоть и моё, но с натяжкой, ведь я его не придумала с нуля, а оптимизировала готовое!
Быстрое определения вхождения символа в список, Fast method to Define symbol by List
 
Цитата
написал:
Aнaстaсия , так вы эти листинги на заводе кодите — я правильно понимаю?
Да, всё верно, кодинг для обработки данных, автоматизации и прочих задач, который требует заказчик!

Цитата
написал:
Excel вам нужен по работе или просто хобби?
Ну как сказать... по сути у меня должность, не связанная с программированием, но т.к. у меня это получается, то меня грузят как раз только этими задачами! Можно сказать, что для работы это не требуется и я могла просто спокойно выполнять свою работу, но один раз помогла по-дружбе и пошло поехало, сарафанное радио... Более сказать не могу, дабы не деанонимизировать себя!

Цитата
написал:
Как обучались VBA?
Тупо взялась помочь человеку и сделала ему простой макрос, который помог ему! Далее курсы с теневых ресурсов, книги, какие-то решения на форумах, тесты и разбирательства в чужом коде! В общем, стандартный путь и полное погружение с задротством (~ 8-11 часов в день с перерывами)! Ещё добавлю, что нужно подтягивать высокоуровневую базу (алгоритмы, структуры данных, определения и формулировки), т.к. на просторах интернета много мусора и отсебятины! Ну и конечно никому не верить, т.к. большинство информации в современном мире просто воруют заимствуют, что требует дополнительной проверки и разбирательства, т.к. не вся заимствованная информация может быть истиной! Как итог:
  1. Тотальное задродство (одаренности нету и это миф, тупо Hard Work и заинтересованность решают);
  2. Помнить, что кругом, в основном, обман и нужно всё проверять и тестить!
Изменено: Aнaстaсия - 22.09.2023 06:06:07
Быстрое определения вхождения символа в список, Fast method to Define symbol by List
 
БМВ, приветствую!
Цитата
написал:
и вот тут баном попахивает.
Ваше право и я даже спорить не буду!
Цитата
написал:
и это тоже рискует быть скрытым и удаленным
Поняла, тему модераторства не подымать!
Быстрое определения вхождения символа в список, Fast method to Define symbol by List
 
Цитата
написал:
Напишу простыню об истории метода, пока время есть)
Эх Лёха, Лёха Лёха, мне с тобой так плохо, душно в комнате как стало и дышать тяжко стало...😁 (без обид)

Ну и Вы расписали конечно, но всё зря, т.к. в большинстве случаев люди сразу оправдываются! А я сделала вывод как раз на основании ваших высказываний и неверных предположений... Ну в прочем кто шарит, тот поймёт!

Цитата
написал:
абсолютно беспочвенны (в который раз)
Ну это только Ваше мнение, не прикреплённое фактами! Тупо на основании своей истории, которая может быть ложной, Вы сделали вывод... Ну дело ваше!

Цитата
написал:
расскажите, пожалуйста, коротко о себе: чем занимаетесь, сколько программируете на VBA, бывали ли на других форумах и, самое интересное, почему именно мои темы?
Тут особо рассказывать нечего, т.к. я начинающая только (~3 года увлекаюсь), работа на заводе, на других форумах не была, вот только недавно решила зарегаться и попробывать что-то сделать. На вас попала, т.к. сама на начальном этапе пыталась всё ускорить до каждой наносекунды, но Вы меня ботом назвали и как-то агрессивно с модератором на меня наехали, начали удалять мои сообщения и вообще в старую учётку зайти не смогла! Пришлось новую открывать, но т.к. к старой я так понимаю доступа не будет (после этой статьи вообще может и эту заблочат, тогда смысла регистрировать заново уже не будет и мы с Вами попрощаемся)!

Цитата
написал:
Думаю, не мне одному будет интересно, где пропадал всё это время хороший VBAшник.
Я бы не назвала себя VBAшником и программистом тоже, скорее кодером, который только вкатывается и начинает разгребать весь информационный мусор и искать истину!



Ладно! Давайте конструктивно перейдём к теме и поставим логическую точку. А пока жду комментарии по поводу кода!
Изменено: Aнaстaсия - 21.09.2023 15:05:49
Быстрое определения вхождения символа в список, Fast method to Define symbol by List
 
Ну и для размышления, хочу Вас огорчить, но когда задача стоит в том, чтобы удалить 1 или 2 символа (sList$ = "." или sList$ = "./"), что в принципе можно прировнять к реальным условиям, то моё решение отрабатывает также, а в большинстве случаев, быстрее:
Код
Private Sub Test_String_DelLR_10()
    Dim aL() As Byte, aR() As Byte
    Dim s$, s2$, sList$, List(), t!, n&

    sList$ = "."
    'sList$ = "./"
    
    s = "sdgfsgsdfsdfsdfsdfsdf"
    s = String$(10, "Q")
    s = sList & s & StrReverse(sList)
    
    String_UniList_ToArr1D_ExistsInFull aL, sList: aR = aL
    
    t = Timer
        For n = 1 To 1000000
            'String_DelLR_AscW s, s2, aL, aR, True, True                     ' 0.5 | 0.5
            'String_DelLR_InStr_Anastasia s, s2, sList, sList, True, True    ' 0.4 | 0.5
        Next n
    Debug.Print Format$(Timer - t, "0.0"), s2
End Sub
Код
len = 100
         
            'String_DelLR_AscW s, s2, aL, aR, True, True                     ' 0.5 | 0.6
            'String_DelLR_InStr_Anastasia s, s2, sList, sList, True, True    ' 0.4 | 0.5
Код
len = 1000
         
            'String_DelLR_AscW s, s2, aL, aR, True, True                    ' 0.6 | 0.7
            'String_DelLR_InStr_Anastasia s, s2, sList, sList, True, True   ' 0.4 | 0.6
Код
len = 5000
         
            'String_DelLR_AscW s, s2, aL, aR, True, True                    ' 1.0 | 1.1
            'String_DelLR_InStr_Anastasia s, s2, sList, sList, True, True   ' 0.5 | 0.6
Код
len = 10000
         
            'String_DelLR_AscW s, s2, aL, aR, True, True                    ' 2.0 | 2.0
            'String_DelLR_InStr_Anastasia s, s2, sList, sList, True, True   ' 0.6 | 0.8
Код
len = 32767
         
            'String_DelLR_AscW s, s2, aL, aR, True, True                    ' 5.7 | 5.8
            'String_DelLR_InStr_Anastasia s, s2, sList, sList, True, True   ' 1.9 | 2.1

Что собственно говоря доказывает правоту моих слов:
Цитата
написал:
Да, конечно, если добавить весь Unicode, то Ваш алгоритм будет отрабатывать быстрее, т.к. проход осуществляется по массиву, а у меня каждый раз бы дергался символ для проверки через Mid$
То есть, чем больше символов Вы захотите удалить, тем быстрее Ваш алгоритм будем отрабатывать по сравнению с моим, но при условии, что длина строки будет небольшой! В противном случае алгоритм будет хуже себя показывать!

Файл прикладываю!
Изменено: Aнaстaсия - 21.09.2023 14:35:31
Быстрое определения вхождения символа в список, Fast method to Define symbol by List
 
Jack Famous, слабая корреляция у Вас в ваших логических умозаключений, ну серьёзно!

Цитата
написал:
тестовый стенд — это что-то, что можно скопировать в модуль, запустить нужную процедуру и увидеть время работы и результат.
Скачивайте файл и запускайте, даже вставлять ничего не нужно! Могу в принципе заняться этим вопросом и раскидать, что такое тестовый стенд и что им может являться, т.к. думаю Вы сами это определение сформировали только на основании своих когнитивных искажений и личного опыта!

Цитата
написал:
(не у компа)
Так как Вы собирались тестить то, если компа нету? Для ознакомления, я код метода выложила. Описала всё подробно! Без компа Вам остается только анализировать данное решение! Всё, лучше не придумаешь)

Цитата
написал:
сознательно упустили, забыли или не знали?
Выберу то, что Вы хотите услышать! Я не знала! Только в чём проблема то, если человек не знает? Проблема, если человек не признает ошибки и не учиться!

В целом вывод из статьи можно сделать такой:
  1. У Вас возникла задача по удалению ненужных символов в строке (слева/справа)!
  2. Вы искали решение и наткнулись на решение по принципу битового массива маску! Как говорил Владимир
    Цитата
    написал:
    Это достаточно распространённый прием.

  3. Вы, на основании распространённого приёма съагрегировали решение, но досконально не разобрались в нём (на это указывают Ваши высказывания):
    Цитата
    написал:
    тоже попробуйте и покажите. Спойлер: результат вам не понравится  
    Скорее всего Вы попытались сделать что-то, и у Вас не вышло (хотя описание было довольно прозрачным и метод интуитивно понятный (без преувеличения я за 3-4 минуты примерно внесла изменения в этот метод)
    Цитата
    написал:
    Сильно сомневаюсь, что вариант на индексах массива мог проиграть — наверное, вы что-то перепутали.
    Нет, это Вы не до конца разобрались в своём алгоритме, и поставили под сомнение мой алгоритм!
В общем, вместо того, чтобы признать, что я сделала неплохое решение и пожать друг другу руки (образно), Вы душите меня странными вопросами и причём уже наговорили так много, что подвергает сомнением, действительно ли Вы автор алгоритма! Или может это видоизменённая копипаста!?

Быстрое определения вхождения символа в список, Fast method to Define symbol by List
 
Jack Famous, какой-то странный Вы) Не пойму, то ли защитная реакция какая-то, то ли что-то другое...

Про байт ответила же на вопрос, чем ответ не устроил? Что Вы хотите от меня услышать?
Цитата
написал:
И не увидите))) Вы ранее сами добавили проверку же! Зачем писать велосипеды)?

Тестовый стенд описала же, но если хотите, пожалуйста. Файл во вложении!
Изменено: Aнaстaсия - 21.09.2023 14:30:19
Быстрое определения вхождения символа в список, Fast method to Define symbol by List
 
Jack Famous, также можно поиграться с количеством символов в строке-шаблоне:
Код
(sList$ = ".,/|\:-") | (sList$ = ".,/|\:-#$%^&()_+}{][...") 
Но, скорее всего особой разницы Вы не заметите!

Да, конечно, если добавить весь Unicode, то Ваш алгоритм будет отрабатывать быстрее, т.к. проход осуществляется по массиву, а у меня каждый раз бы дергался символ для проверки через Mid$, но оно надо это? + Эта задача лишена логики для применения в реальной жизни!  
Быстрое определения вхождения символа в список, Fast method to Define symbol by List
 
Цитата
написал:
Сильно сомневаюсь, что вариант на индексах массива мог проиграть — наверное, вы что-то перепутали.
Да что же Вы всё сомневаетесь то) И тесты элементарные, без подвоха, тупо генерируется строка с одним символом разной длины:
Код
s = sList & string$(100,"Q") & StrReverse(sList)
s = sList & string$(1000,"Q") & StrReverse(sList) 
s = sList & string$(5000,"Q") & StrReverse(sList) 
s = sList & string$(10000,"Q") & StrReverse(sList)
s = sList & string$(32767,"Q") & StrReverse(sList)
И далее просто пропускается строка через цикл с заранее подготовленными методами:
Код
    For n = 1 To 1000000
        'String_DelLR_AscW s, s2, aL, aR, True, True                    
        'String_DelLR_InStr_Anastasia s, s2, sList, sList, True, True   
        'String_DelLR_InStr_Update s, s2, sList, sList, True, True     
        'String_DelLR_Bytes s, s2, sList$                              
        'String_DelLR_InStr s, s2, sList, sList, True, True            
    Next n
По поводу "Сильно сомневаюсь, что вариант на индексах массива мог проиграть..." Вы упускаете одну важную деталь в вашем алгоритме, а именно:
Код
aBt = sIn ' Преобразование строки в байт-массив
Это преобразование также влияет на производительность кода, и чем длиннее строка, тем медленнее будет конвертация! Но убрать его нельзя, т.к. логика построена именно на этом!
Цитата
написал:
И да, строка не обязательно может быть ограничена возможностями ячейки. Строки можно получать не только с листа.
За это я в курсе, просто мы рассматриваем алгоритм вроде для решения реальных задач, а реальные задачи в основном у большинства связаны с данными именно на листе Excel!
Цитата
написал:
добавлял к ним список символов для удаления слева и справа (вариант без символов, с 1, с10ю, с обоих сторон, с одной из)
На результат тестирования это никак не повлияет! У вас стоят булевые идентификаторы, которые определяют, нужно ли удалять символы с той или иной стороны! Простыми словами: Вы хотите удалить с обоих сторон символы, то заняло бы это примерно 1 условную единицу! Далее хотите удалить только слева или права, то результат будет составлять ~0.5 (противоположный алгоритм просто не запуститься), без символов не вижу смысла запускать, тогда зачем алгоритм сам), Но если так нужно, то все алгоритмы выдадут результат приближенный к 0, т.к. сама логика не выполниться, за исключением алгоритма, требующих преобразование в байт-массив:
Код
aBt = sIn ' Это замедлит вашу основную процедуру!

' А практически всё ниже не выполниться!
If fL Then ' пропуск
    For b = 0 To UBound(aBt) Step 2
        If aL(aBt(b) + (256 * aBt(b + 1))) = 1 Then l = l + 1 Else Exit For
    Next b
End If

If l = ll Then sOut = "": Exit Sub

If fR Then 'пропуск
    For b = UBound(aBt) - 1 To 0 Step -2
        If aR(aBt(b) + (256 * aBt(b + 1))) = 1 Then r = r + 1 Else Exit For
    Next b
End If
Можно дополнительно добавить инструкцию на проверку шаблонной строки, но не вижу смысла, т.к. скорее всего никто алгоритм не будет запускать с пустой строкой-шаблоном. Это же бред! Но Вашему алгоритму это не помешает, чтобы ненужное преобразование изолировать, на случай, если найдется такой нехороший человек 😁

Цитата
написал:
Про потерянный 2ой байт так ничего и не увидел.
И не увидите))) Вы ранее сами добавили проверку же! Зачем писать велосипеды)?
Изменено: Aнaстaсия - 21.09.2023 09:12:40
Быстрое определения вхождения символа в список, Fast method to Define symbol by List
 
ZVI, спасибо за разъяснения и приветствие 👍
Быстрое определения вхождения символа в список, Fast method to Define symbol by List
 
Доброго дня) По порядку:

Цитата
написал:
Очень странная конструкция
Алгоритм построен на принципе полного перебора и данная строка служит критерием для определения, входит ли просматриваемый символ в перечень шаблонных символов! Добавлю комментарий:
Код
...
    ' Первый цикл перебирает все байты исходной строки слево-направо
    For I = LB1 To UB1 Step 2
        ' Второй цикл перебирает все байты строки с символами, которые нужно удалить
        For J = LB2 To UB2 Step 2
            ' Если просматриваемый байт совпадает с байтом символа для удаления, то делаем Flag = True и выходим из цикла, 
              т.к. мы убедились что данный символ нужно удалить и можно переходить к проверке следующего | В противном случае мы увеличиваем счетчик на 1 
            If SB(I) = SB1(J) Then Flag = True: Exit For Else N = N + 1
        Next J
        ' Если Flag = True, тогда обнуляем счетчик и меняем состояние флага, т.к. мы понимаем, что символ нужно удалить и требуется проверить следующий
        ' Если Flag = False, тогда сверяем счетчик с количеством символов для перебора, то есть убеждаемся, что например N = 7, 
        ' и символов для удаления в шаблоне тоже 7. Len("./|\_-?") = 7. Можно реализовать и без счетчика, но счетчик был добавлен с целью
        ' убедится в правильности логики алгоритма!
        If Not Flag Then If N = NN& Then Exit For Else N = 0 Else N = 0: Flag = False
    Next I
...
Цитата
написал:
тоже попробуйте и покажите. Спойлер: результат вам не понравится  
Ну как сказать... Мне всё понравилось. Видимо немного Вы по-другому реализовали моё предложение.
Результаты всех методов ниже:

Код String_DelLR_InStr_Update - это ваш обновленный код в #30 комментарии.
Код String_DelLR_InStr_Anastasia:
Код
Sub String_DelLR_InStr_Anastasia(sIn$, sOut$, Optional sL$, Optional sR$, Optional fL As Boolean, Optional fR As Boolean)
    Dim ll&, l&, n&, I_S&, I_F&
    
    ll = Len(sIn)
    If ll = 0 Then Out = sIn: Exit Sub
    
    I_S = 1
    I_F = ll
    
    If fL Then
        Do Until (InStr(sL, Mid$(sIn$, I_S, 1)) = 0)
            I_S = I_S + 1: If I_S > I_F Then Out = "": Exit Sub
        Loop
    End If
    
    If fR Then
        Do Until (InStr(sR, Mid$(sIn$, I_F, 1)) = 0)
            I_F = I_F - 1: If I_S > I_F Then Out = "": Exit Sub
        Loop
    End If
    
    sOut = Mid$(sIn, I_S, I_F - I_S + 1)

End Sub

Тесты соответственно на разных входных данных (разная длина строк):

Код
Len(s) = 10       
        'String_DelLR_AscW s, s2, aL, aR, True, True                   ' 0.8
        'String_DelLR_InStr_Anastasia s, s2, sList, sList, True, True  ' 1.3
        'String_DelLR_InStr_Update s, s2, sList, sList, True, True     ' 1.7
        'String_DelLR_Bytes s, s2, sList$                              ' 1.9
        'String_DelLR_InStr s, s2, sList, sList, True, True            ' 2.4
Код
Len(s) = 100        
        'String_DelLR_AscW s, s2, aL, aR, True, True                   ' 0.9
        'String_DelLR_InStr_Anastasia s, s2, sList, sList, True, True  ' 1.3
        'String_DelLR_InStr_Update s, s2, sList, sList, True, True     ' 1.9
        'String_DelLR_Bytes s, s2, sList$                              ' 1.9
        'String_DelLR_InStr s, s2, sList, sList, True, True            ' 2.6    
Код
Len(s) = 1000
        'String_DelLR_AscW s, s2, aL, aR, True, True                   ' 1.0
        'String_DelLR_InStr_Anastasia s, s2, sList, sList, True, True  ' 1.3
        'String_DelLR_Bytes s, s2, sList$                              ' 1.9
        'String_DelLR_InStr_Update s, s2, sList, sList, True, True     ' 2.0
        'String_DelLR_InStr s, s2, sList, sList, True, True            ' 3.0
Код
Len(s) = 5000
        'String_DelLR_AscW s, s2, aL, aR, True, True                   ' 1.3
        'String_DelLR_InStr_Anastasia s, s2, sList, sList, True, True  ' 1.3
        'String_DelLR_Bytes s, s2, sList$                              ' 2.2
        'String_DelLR_InStr_Update s, s2, sList, sList, True, True     ' 2.8
        'String_DelLR_InStr s, s2, sList, sList, True, True            ' 4.6
Код
Len(s) = 10000
        'String_DelLR_InStr_Anastasia s, s2, sList, sList, True, True  ' 1.6
        'String_DelLR_AscW s, s2, aL, aR, True, True                   ' 2.2
        'String_DelLR_Bytes s, s2, sList$                              ' 2.8
        'String_DelLR_InStr_Update s, s2, sList, sList, True, True     ' 4.9
        'String_DelLR_InStr s, s2, sList, sList, True, True            ' 9.7
Код
Len(s) = 32767 ' Максимальное количество знаков в ячейке Excel
        'String_DelLR_InStr_Anastasia s, s2, sList, sList, True, True  ' 3.0
        'String_DelLR_Bytes s, s2, sList$                              ' 5.8
        'String_DelLR_AscW s, s2, aL, aR, True, True                   ' 6.3
        'String_DelLR_InStr_Update s, s2, sList, sList, True, True     ' 24.8
        'String_DelLR_InStr s, s2, sList, sList, True, True            ' 45.8
Как можем заметить, то использование одного Mid$ эффективнее + мы не меняем исходную строку, что значительно замедляем все вышеперечисленные алгоритмы с использованием InStr, кроме 2-x моих! Также отмечу, что при увеличение входных данных, алгоритмическая сложность растет нелинейно! Особенно это видим у методов String_DelLR_InStr и String_DelLR_InStr_Update. Меньшее отклонение от линейной сложности алгоритма мы наблюдаем у метода String_DelLR_InStr_Anastasia. На начальных тестах (до Len(s) = 5000 включительно) мы вообще имеем константную сложность алгоритма!

Как итог: Чтобы не париться, можно использовать String_DelLR_InStr_Anastasia и не таскать с собой дополнительно код String_UniList_ToArr1D_ExistsInFull для метода String_DelLR_AscW. Стоит признать, что данный метод шустрый, но незначительно! Но для любителей Performance (максимально быстрых решений) можно конкатенировать два решения в что-то подобное (добавить промежуточный код):
Код
    ll = Len(sIn)
    If ll = 0 Then Out = sIn: Exit Sub
    If ll > 5000 Then
        String_DelLR_InStr s, s2, sList, sList, True, True
    Else
        String_DelLR_AscW s, s2, aL, aR, True, True
    End If
Под String_DelLR_InStr, в данном примере, я имею ввиду метод String_DelLR_InStr_Anastasia, просто убрала имя чтобы не говнокодить 😁  
Изменено: Aнaстaсия - 21.09.2023 07:11:01
Быстрое определения вхождения символа в список, Fast method to Define symbol by List
 
Цитата
написал:
Обновил вариант на InStr
Без негатива, только конструктивная критика!
Каждый раз, при каждой итерации Вы меняете строку методами Left$ и Right$! Это очень негативно сказывается на производительности при больших строках, тоесть если отойти от примера в коде и протестировать его на более большом примере, то Вы получите проседание в производительности! И мой код в выигрыше! Соответвено алгоритм лучше переписать на счетчики, которые будут запоминать текущее состояние строки!

Так Вы будете работать только с одной строкой, но при этом не будете её изменять, т.к. изменения строк - это довольно дорогие операции! Мой алгоритм на этом и основан и получение подстроки вычисляется только один раз!
Изменено: Aнaстaсия - 20.09.2023 15:49:23
Быстрое определения вхождения символа в список, Fast method to Define symbol by List
 
Цитата
Jack Famous,
Цитата
написал:
• вылетит в дебаг при переданной пустой строке    
• вылетит в дебаг при переданной строке, полностью состоящей из символов для удаления    
• не может работать с разными списками для начала/конца, а также выборочно удалять только с начала/конца.    
•  не учитывает второй байт символов при проверке.Это означает, что символы с ненулевым вторым байтом дадут ложное совпадение.    
• избыточная проверка: If UBound(SB, 1) Mod 2 Then, т.к. a() As Byte = s это всегда (насколько мне известно) от 0 до 2 * Len(s) -1, то есть UBound(SB, 1) — это всегда нечётное число.
Открою окно, а то душно стало!
Это всё решается парочкой If-ов и задача с моей стороны была предоставить альтернативную логику решения задачи, а не выдать отполированное решение с учетом обработки всех ситуаций (потраченное время на составление кода - не более 1 часа)!

По поводу "избыточная проверка"... Согласна, можно так
Код
x = UBound(SB, 1) - 1
Просто экспериментировала с байтами и строками, в итоге не исправила старый вариант, где тесты проводила с массивом символов на финальный вариант с байт-массивом!

Цитата
написал:
Код сильно неочевидный, сложный
Ну для кого как:
  1. Конвертируем исходные данные и строку-шаблон в байт-массивы;
  2. Перебираем эти массивы по нечетным индексам и выходим из цикла, когда убеждаемся, что просматриваемый байт не входит в состав байтов-шаблона!
  3. На основании сохранившихся счетчиков циклов, выдергиваем нужный текст!
  4. Всё, иззи-пизи! Полный перебор (Brute Forse) по сути!
Цитата
написал:
при этом полно абсолютно ненужных действий (в циклах ещё есть) и присутствуют ошибки
Каждое действие важно для решения поставленной задачи, за исключением избыточного IF, и выше я прояснила это и согласилась! Но вопрос я всё же должна задать) Приведите, пожалуйста примеры, где полно ненужных действий "(в циклах ещё есть)" и ошибок! А то такие заявления попахивают воздуханством (без негатива)!

И спасибо конечно за не новичка, но попрошу не льстить!
Быстрое определения вхождения символа в список, Fast method to Define symbol by List
 
Marat Ta, приветствую, тут на самом деле всё просто! Просто кажется что сложно, но Вы правы в одном, что данная тема не относится к Excel, а больше про "алгоритмическое задродство"!

Объясню своими словами: У вас есть например строка "-пример//" И вам необходимо удалить лишние символы в начале и конце по шаблону (в данном случае это "-","/") чтобы получить на выходе голую строку "пример"! И все вышеперечисленные алгоритмы в принципе этим и занимаются!

Но также дополню, что если в примере будет "-при-ме/р//", то на выходе Вы получите "при-ме/р", т.к. алгоритм заточен только на начало и конец строки!

Надеюсь объяснила понятно) Если нет, то пожалуйста дайте знать, я попытаюсь ещё раз 😁
Изменено: Aнaстaсия - 20.09.2023 13:06:33
Быстрое определения вхождения символа в список, Fast method to Define symbol by List
 
Цитата
написал:
Aнaстaсия , совсем забыл — ваш код принимает только один список, а остальные испытуемые могут работать с разными списками символов для удаления слева и справа. А также могут удалять только слева/справа.
Добавить два If и два булевых аргумента в начале метода, похоже это действительно проблема 😁

Jack Famous, прощайте и в коде разберитесь, прежде чем негативно аргументировать!
Изменено: Aнaстaсия - 20.09.2023 12:32:10
Быстрое определения вхождения символа в список, Fast method to Define symbol by List
 
Цитата
написал:
диалог должен быть конструктивным.
Что же для Вам тогда конструктивно)? Похоже у нас разные понятия! У Вас конструктивно - это когда Вам выгодно похоже!
Цитата
написал:
Прощание с вами произошло из-за того, что вы грубо нарушили правила форума, создав клон учётной записи — теперь вас забанят (и все новые клоны тоже).
Правильное решение для немного шаряших новичков (это сарказм)
Цитата
написал:
Создавать массивы для работы моей функции нужно только один раз перед прогоном. Подразумевается, что все строки нужно проверить по одному и тому же списку символов — это реальная задача. Интересно, как вы представляете себе иной вариант работы.
Ваша реальная задача и описание имеют слабую корреляцию! Переделать тесты тогда нужно, но это опять не конструктивно!

Ладно, я больше не буду говорить своё мнение на этом форуме, а Вам посоветую сходить на курсы гуглёжки и подтянуть базу (я серьёзно), чтобы людей не путать!
Страницы: 1 2 След.
Loading...