Поиск по подстроке в таблице значений. По принципу "начинается с"

07.04.21

Разработка - Универсальные функции

Часто сталкивался с задачей поиска по подстроке в таблице значений. Ну, например, в таблице нужно найти всех Петровых, или, например, все строки, в которых значение в Колонке Х начинается на "Бел". Вариантов для себя нашел всего 2. Первый - это перебор и сравнение со значением поиска, а второй - поместить во временную таблицу и через Подобно вытащить значения. Но все это было медленно, примерно на 130 000 поиск нужных значений занимал более 1,5 секунд (это перебором), а помещение во временную таблицу не всегда возможно и тоже более секунды. Тогда сделал сделал так, отсортировал таблицу по нужному мне столбцу и далее уже из этой таблицы выбирал нужные мне данные. И скорость возросла значительно, теперь то, что я ранее выбирал за 1,5 секунды, выбирается не более 10 милисекунд.

 

Часто сталкивался с задачей поиска по подстроке в таблице значений. Ну, например, в таблице нужно найти всех Петровых, или, например, все строки, в которых значение в Колонке Х начинается на "Бел". Вариантов для себя нашел всего 2. Первый - это перебор и сравнение со значением поиска, а второй - поместить во временную таблицу и через Подобно вытащить значения. Но все это было медленно, примерно на 130 000 поиск нужных значений занимал более 1,5 секунд (это перебором), а помещение во временную таблицу не всегда возможно и тоже более секунды. Тогда сделал сделал так, отсортировал таблицу по нужному мне столбцу и далее уже из этой таблицы выбирал нужные мне данные. И скорость возросла значительно, теперь то, что я ранее выбирал за 1,5 секунды, выбирается не более 10 милисекунд.

На этом абзаце мой писательский талант иссяк. Поэтому далее в телеграфном стиле.

 

Описание

Создано 2 функции.

ПоискДихотомияПоСортированнойТаблице - это основная функция, которая возвращает массив найденных строк, если ничего не найдено, то вернется пустой массив.

Параметры:

тТаблица - таблица значений, отсортированная по колонке поиска по возрастанию. 

КолонкаПоиска - Имя колонки, по которой собственно ищем, таблица тТаблица обязательно должна по ней быть отсортирована, иначе метод не работает.

ПоисковаяСтрока - строка, вхождение "слева" которой ищем в значениях колонки поиска

ТочныйПоиск - это признак того, что нужно искать одно конкретное значение. (Собственно аналог найтиСтроки, здесь он для универсальности, но вроде работает тоже побыстрее, правда я не проверял)

УчитыватьРегистр - признак того, что при сравнении значений необходимо учитывать регистр, т.е. если ищем "петр", то "Петров" не будет найден.

 

Функция ПолучитьЗначениеДляСравнения - модифицирует значение в очередной строке из Таблицы для того, чтобы его можно было сравнить с ПоисковойСтрокой.

Код функция здесь. Можно брать и вставлять в свои модули. 

Функция ПоискДихотомияПоСортированнойТаблице(тТаблица,КолонкаПоиска,ПоисковаяСтрока,ТочныйПоиск = Ложь,УчитыватьРегистр=ложь) Экспорт
    
        Результат = Новый Массив;
        ПОиск = ?(УчитыватьРегистр,ПоисковаяСтрока,ВРег(ПоисковаяСтрока));
        Длина=СтрДлина(ПОиск);    
        К = тТаблица.Количество()-1;
        нИнд = Цел(К/2);
        лево = 0;
        право = К;
        Пока Истина Цикл 
            
            нстр = тТаблица.Получить(нИнд);
            Если нИнд=лево или нИнд=право Тогда 
                Прервать;
            КонецЕсли;
            Если ПолучитьЗначениеДляСравнения(нстр,КолонкаПоиска,Длина,ТочныйПоиск,УчитыватьРегистр)=ПОиск тогда
                Прервать;
            КонецЕсли;
            
            Если ПолучитьЗначениеДляСравнения(нстр,КолонкаПоиска,Длина,ТочныйПоиск,УчитыватьРегистр)>ПОиск тогда
                право = нИнд;
                нИнд = Цел(лево+(нИнд-лево)/2);
            КонецЕсли;
            
            Если ПолучитьЗначениеДляСравнения(нстр,КолонкаПоиска,Длина,ТочныйПоиск,УчитыватьРегистр)<ПОиск тогда
                лево = нИнд;
                нИнд = Цел(право-(право -нИнд)/2);
            КонецЕсли;
            
            
            
        КонецЦикла;
        
        
        Если ПолучитьЗначениеДляСравнения(нстр,КолонкаПоиска,Длина,ТочныйПоиск,УчитыватьРегистр)=ПОиск тогда
            сч=нИнд;
            Пока ПолучитьЗначениеДляСравнения(нстр,КолонкаПоиска,Длина,ТочныйПоиск,УчитыватьРегистр)=ПОиск Цикл
                Результат.Вставить(0,нстр); 
                сч=сч-1;
                Если сч<0 Тогда 
                    Прервать;
                КонецЕсли;
                нстр = тТаблица.Получить(сч);
                
            КонецЦикла;
            сч=нИнд+1;
            Если сч<=К Тогда 
                нстр = тТаблица.Получить(сч);
                Пока ПолучитьЗначениеДляСравнения(нстр,КолонкаПоиска,Длина,ТочныйПоиск,УчитыватьРегистр)=ПОиск Цикл 
                    Результат.Добавить(нстр);
                    сч=сч+1;
                    Если сч>К Тогда 
                        Прервать;
                    КонецЕсли;
                    нстр = тТаблица.Получить(сч);
                    
                КонецЦикла;
                
            КонецЕсли;
        КонецЕсли;
        
        Возврат Результат;

    
    
    
    
КонецФункции

Функция ПолучитьЗначениеДляСравнения(СтрокаТаблицы,КолонкаПоиска,КоличествоСимволовПоиска,ТочноеСовпадение,УчитыватьРегистр)
    
    Если ТочноеСовпадение Тогда 
        Результат = ?(УчитыватьРегистр,СтрокаТаблицы[КолонкаПоиска],ВРег(СтрокаТаблицы[КолонкаПоиска]));
    иначе
        Результат = ?(УчитыватьРегистр,Лев(СтрокаТаблицы[КолонкаПоиска],КоличествоСимволовПоиска),Лев(ВРег(СтрокаТаблицы[КолонкаПоиска]),КоличествоСимволовПоиска));
    КонецЕсли;
    Возврат Результат;
    
КонецФункции

 

Как можно использовать

 

 Например, у нас есть таблица

ФИО Оклад
Иванов Иван Иванович 600
Петров Иван Иванович 300
петров Николай Петрович 700
сидоров Иван Иванович 400


Нам нужно выбрать всех Петровых.

Сначала мы сортируем таблицу по ФИО. Желательно этот метод применять таким образом, что таблица отсортирована один раз, а сам метод применяется много раз.

А далее

РезультатМассивСтрок = ПоискДихотомияПоСортированнойТаблице(таблицаСФИО,"ФИО","петров ",ложь,ложь);

В итоге в результатМассив попадут строки.

ФИО Оклад
Петров Иван Иванович 300
петров Николай Петрович 700

 

Я например этот метод использовал для автоподстановки в поле ввода. (таблица была более 130000 строк).

Послесловие

Коллеги, жду от Вас комментарии. А может, кто-то знает более быстрый метод, а я тут изобретаю велосипед.

 

Вступайте в нашу телеграмм-группу Инфостарт

ТаблицаЗначений таблица поиск дихотомия

Вы можете заказать платную адаптацию этой статьи под ваши задачи на «Бирже заказов».

  • 0% комиссии — оплата напрямую исполнителю;
  • Исполнители любого масштаба — от отдельных специалистов до команд под проект;
  • Прямой обмен контактами между заказчиком и исполнителем;
  • Безопасная сделка — при необходимости;
  • Рейтинги, кейсы и прозрачная система откликов.

См. также

Загрузка и выгрузка в Excel Универсальные функции Программист 1С:Предприятие 8 Россия Бесплатно (free)

Описанный ниже подход позволяет в три шага заполнять формулы в Excel файлы, вне зависимости от ОС сервера (MS Windows Server или Linux). Подход подразумевает отказ от работы с COM-объектом в пользу работы через "объектную модель документа" (DOM).

30.10.2025    7688    Abysswalker    11    

49

Универсальные функции Работа с интерфейсом Программист 1С:Предприятие 8 Бесплатно (free)

Порой необходимо временно отключить расширение 1С, не удаляя его, чтобы не потерять данные. Но в этом случае при каждом запуске всем будет лезть уведомление о неактивном расширении, хотя очевидно, это техническая информация, которой не стоит лишний раз пугать пользователей.

14.05.2025    12945    DeerCven    15    

64

Универсальные функции Программист 1С:Предприятие 8 1C:Бухгалтерия Бесплатно (free)

Благодаря этим пяти строчкам можно больше не заморачиваться с загрузкой из внешних файлов. Пользуюсь везде, всегда и постоянно.

21.05.2024    65967    dimanich70    87    

177

Универсальные функции Программист 1С:Предприятие 8 1C:Бухгалтерия Абонемент ($m)

Задача: вставить картинку из буфера обмена на форму средствами платформы 1С.

1 стартмани

18.03.2024    8750    7    John_d    13    

59

Универсальные функции Программист Стажер 1С:Предприятие 8 1C:Бухгалтерия Бесплатно (free)

Пришлось помучиться с GUID-ами немного, решил поделиться опытом, мало ли кому пригодится.

12.02.2024    82677    atdonya    31    

75

Универсальные функции Программист 1С:Предприятие 8 Бесплатно (free)

На заключительных этапах, когда идет отладка или доработка интерфейса, необходимо много раз переоткрыть внешний объект. Вот один из способов автоматизации этого.

30.11.2023    12762    ke.92@mail.ru    18    

68
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. Activity 3 07.04.21 13:42 Сейчас в теме
Так в данном случае получается поиск не по подстроке, а именно по началу строки или точному соответствию значения и строки поиска, что расходится с понятием поиск по подстроке

Или я ошибаюсь?
2. MikeI 74 07.04.21 18:31 Сейчас в теме
(1)
Так в данном случае получается поиск не по подстроке, а именно по началу строки или точному соответствию значения и строки поиска, что расходится с понятием поиск по подстроке
.

Начало строки - это частный случай подстроки, поэтому я в заголовке и уточнил способ поиска, что бы не создавалось ложное ощущение что поиск происходит по любой подстроке
3. TMV 1 08.04.21 13:13 Сейчас в теме
Ну т.е. достаточно было отсортировать значения в колонке?
4. MikeI 74 08.04.21 14:06 Сейчас в теме
(3)Вы про пример? В статье таблица некорректно показана, она конечно должна быть отсортирована по колонке ФИО. Просто когда не 4 записи , а 100 000 эффект перед обычным перебором налицо.
5. Cyberhawk 135 10.04.21 20:35 Сейчас в теме
на 130 000 поиск нужных значений занимал более 1,5 секунд
В какой момент инициализируется такая ТЗ?
6. MikeI 74 11.04.21 13:30 Сейчас в теме
(5) Таблица инициализируется и сортируется один раз до начала многократного применения процедуры. Я например ее использовал для динамического формирования списка выбор в элементе
7. Cyberhawk 135 11.04.21 14:27 Сейчас в теме
(6) А что является источником данных для формирования ТЗ такого размера? Данные выбираются из какой-то таблицы БД?
8. MikeI 74 11.04.21 14:32 Сейчас в теме
(7) Сторонние данные. Например получение данных с какого-нибудь сайт. Когда значения нужны, а но не нужно записывать их в базу данных 1С. Для пример список Брендов на ОЗОНе.
9. Cyberhawk 135 11.04.21 14:49 Сейчас в теме
(8) А получение с сайта ста тысяч строк (полагаю, как минимум состоящих из пары "ИД - представление") быстро происходит?
Это делается ХТТП-запросом?
10. MikeI 74 11.04.21 14:53 Сейчас в теме
(9) Нет это не быстро. Но это уже данность, и получается один раз. А далее много много раз используется поиск значений полученной таблице. Например Http-запросом
11. Cyberhawk 135 11.04.21 14:58 Сейчас в теме
(10) А источник данных (сайт) не предоставляет возможность получать данные, удовлетворяющие отбору?
12. MikeI 74 11.04.21 15:03 Сейчас в теме
(11) Во-первых. Я привел для примера какие данные, могут. А так это может быть любая таблица значений , полученная любыми способами. А во вторых , получение данных сайта будет происходить дольше, если мы х ним обращаемся много раз, нежели чем при выборке максимального количества данных за один раз.
13. Cyberhawk 135 11.04.21 15:33 Сейчас в теме
(12)
это может быть любая таблица значений , полученная любыми способами
Интересовал конкретный сценарий, в котором пользователю может понадобиться ТЗ на 100+ тысяч строк.
получение данных сайта будет происходить дольше, если мы х ним обращаемся много раз, нежели чем при выборке максимального количества данных за один раз
А сколько в среднем операций поиска выполняет пользователь по такой большой ТЗ? И как реализовано удерживание ТЗ в памяти в течение времени жизни сеанса пользователя?
14. MikeI 74 11.04.21 15:58 Сейчас в теме
(13)
И как реализовано удерживание ТЗ в памяти в течение времени жизни сеанса пользователя?
средствами платформы.

Про сценарий - Например выбор бренда из списка более 130 тыс. с помощью ввода начальных символов бренда. Динамически формируется список выбора
15. pentanom 32 18.01.22 13:03 Сейчас в теме
А Петрович тоже попадает в выборку?
16. slicem 12 19.01.23 11:20 Сейчас в теме
Блин! Идея сравнивать строки на больше меньше - шикарная. Никогда бы не додумался. Спасибо.
17. user1656634 01.02.23 15:49 Сейчас в теме
Функции помогли решить важную задачу по поиску нужного значения в строке, СПАСИБО!

Только хотел уточнить действие строки
нИнд = Цел(К/2);


из за деления на 2 последнюю и нечетную строку функция не видит.
18. MikeI 74 04.02.23 19:23 Сейчас в теме
С граничными значениями действительно были проблемы. А вот с нечётной строкой, рано или поздно найдется значение когда останется 2 значения
Для отправки сообщения требуется регистрация/авторизация