Ещё немного функционального стиля в 1С или Как нам отфильтровать таблицу значений

16.05.20

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

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

Возникла задача.
Есть таблица значений с колонкой Период типа Дата.

Как нам отфильтровать таблицу и выбрать только те строки, которые, например, укладываются в определенный диапазон?

Встроенная функция Скопировать(...)  с отбором строк по переданной структуре нам в данном случае не помощник - соответствие не точное.

Перебор - некрасиво и громоздко.

Загрузка ТЗ во временную таблицу запроса и отбор им - стрельба из пушки по воробьям.

Немного покумекал и придумал следующее:

ОтфильтрованнаяТЗ = ФильтрТЗ(ТЗ, "{ИмяКолонки1} + {ИмяКолонки2} <= {ИмяКолонки3} >> {ИмяКолонки2} <> 0");

Функция принимает в качестве аргумента таблицу значений и последовательно применяет к ней условия, разграниченные разделителем >> - получается что-то вроде конвейера.

Значение в фигурных скобках обозначает значение в соответствующей колонке. В итоге выражение должно давать в результате Истина или Ложь, в зависимости от этого строка ТЗ будет передана в обработку на следующий этап конвейера.

При проверке условия применяется Вычислить(...), так что при написании условий учитывайте имеющиеся ограничения.

Сама функция выглядит достаточно просто, но, возможно, её можно упростить и ещё:

Функция Фильтр(Знач ТЗ, ВыражениеФильтрации) Экспорт
	МассивВыражений = МассивВыражений(ВыражениеФильтрации);
	
	Для Каждого Выражение Из МассивВыражений Цикл
		ПромежуточнаяТЗ = ТЗ.СкопироватьКолонки();
		
		Для Каждого СтрТЗ Из ТЗ Цикл
			Если Вычислить(Выражение) Тогда
				ЗаполнитьЗначенияСвойств(ПромежуточнаяТЗ.Добавить(), СтрТЗ);
			КонецЕсли;
		КонецЦикла;
		
		ТЗ = ПромежуточнаяТЗ;
	КонецЦикла;
	
	Возврат ТЗ;
КонецФункции

Функция МассивВыражений(ВыражениеФильтрации)
	ВыражениеРазделенное = СтрРазделить(СтрЗаменить(ВыражениеФильтрации, ">>", "$"), "$", Ложь);
	МассивВыражений = Новый Массив;
	
        Для Каждого Выражение Из ВыражениеРазделенное Цикл
		ВыражениеОбработанное = СтрЗаменить(Выражение, "{", "СтрТЗ.");
		ВыражениеОбработанное = СтрЗаменить(ВыражениеОбработанное, "}", "");
		
		МассивВыражений.Добавить(ВыражениеОбработанное);
	КонецЦикла;
	
	Возврат МассивВыражений;
КонецФункции

 

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

См. также

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

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

30.10.2025    3458    Abysswalker    8    

45

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

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

14.05.2025    6400    DeerCven    15    

57

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

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

21.05.2024    48854    dimanich70    83    

170

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

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

1 стартмани

18.03.2024    7317    6    John_d    13    

59

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

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

12.02.2024    61093    atdonya    31    

69

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

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

30.11.2023    9114    ke.92@mail.ru    17    

68
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. Steelvan 315 16.05.20 12:07 Сейчас в теме
Скорость своего творчества проверял ?
Новиков; t278; awk; r2d255; +4 Ответить
2. CyberCerber 899 16.05.20 15:45 Сейчас в теме
Но что-то я не понял, чем это лучше простого перебора? Тут даже несколько переборов будет, на каждую часть условия. И если по первой части отобрали почти все строки, мы опять их все проходить будем...
Тогда уж можно было передавать полноценное условие на строку вида "Колонка1 = А И Колонка2 < Б ИЛИ Колонка3 = В". Так мы сразу проверяем полное условие за один проход, можем использовать ИЛИ и т.д.
Deslime; wolfsoft; gubanoff; Xershi; vladimirmatancev; +5 Ответить
3. GlebHappy 117 16.05.20 20:40 Сейчас в теме
(2) Да, такой вариант будет работать - но не потеряется ли читаемость условия?
5. CyberCerber 899 17.05.20 05:41 Сейчас в теме
(3) Как по мне, оно будет более читаемое, чем ваше, потому что это всем знакомый формат, а не что-то новое.
4. PowerBoy 3485 16.05.20 22:10 Сейчас в теме
Запросом будет быстрей, на больших таблицах - точно.
ixijixi; nomad_irk; vladimirmatancev; +3 Ответить
13. ImHunter 341 18.05.20 08:05 Сейчас в теме
(4) Весьма спорное утверждение;)
Запросом будет быстрей, на больших таблицах - точно.

Как по-твоему ТЗ попадает на сервер? Делается куча запросов по передаче и вставке каждой строки ТЗ во временную таблицу БД. Т.е., сам запрос, вероятно, быстро отработает. Но будет куча накладных расходов.

Насчет (0) - выглядит на мой взгляд красиво. Обязательно попробую попробовать.
14. nomad_irk 82 18.05.20 09:57 Сейчас в теме
(13)А ничего, что ТЗ на клиенте не умеет жить от слова совсем? :)
16. ImHunter 341 18.05.20 10:03 Сейчас в теме
(14) Как бы, ну и что? К статье это вообще не имеет отношения. Запрос, например, тоже на клиенте не живет.
17. nomad_irk 82 18.05.20 10:05 Сейчас в теме
(16) Так зачем ТЗ передавать на сервер? Она там уже всегда.
18. ImHunter 341 18.05.20 10:24 Сейчас в теме
(17) Имеется в виду передача ТЗ в СУБД для выполнения запроса. Ведь Запрос только с данными СУБД и работает.
При использовании параметра запроса типа ТЗ, платформа неявно создает ВТ. Отсюда, кстати, требование типизации ТЗ. И потом происходит построчное наполнение ВТ.
19. nomad_irk 82 18.05.20 10:27 Сейчас в теме
(18)В любом случае, это работает быстрее, т.к. реализуется средствами платформы.
20. ImHunter 341 18.05.20 10:29 Сейчас в теме
(19) А мы тут никакие ВК и не обсуждаем;) Все только платформой и делается.
6. acanta 17.05.20 06:13 Сейчас в теме
По стандартам 7.7 вычислить/шаблон было не 1с совместимо, из за невозможности синтаксического контроля. Хотя позже я видела несколько тиражных решений, со статусом 1с совместимо, использующих эти методы.
В 8ке что то изменилось (кроме того что в поставку стало возможным не включать код)?
7. vladimirmatancev 24 17.05.20 09:48 Сейчас в теме
Перебор - некрасиво и громоздко.

Для Каждого СтрТЗ Из ТЗ Цикл

А где тут без перебора?
Deslime; D_astana; CyberCerber; wolfsoft; gubanoff; t278; awk; +7 Ответить
8. awk 745 17.05.20 10:45 Сейчас в теме
(7) Статья явный перебор. :)
CyberCerber; gubanoff; wazup666; +3 Ответить
9. acanta 17.05.20 11:08 Сейчас в теме
Обычная ситуация, допустим у нас таблица значений с кодами товаров, периодами и суммами продаж. Необходимо дополнить ее колонками с какими то расчетным показателями, реквизитами товаров, наименованием и т.п.
В запросе делаем соединение тз со справочником и вычисляем все что вычисляется.
А если периоды нужно разделить, то соединяем тз с самой тз столько раз, сколько максимально периодов может получиться.
После чего отбираем по требуемому диапазону. Так?
10. logarifm 1131 17.05.20 19:23 Сейчас в теме
Нахрена изобретать сей велосипед, когда ТЗ можно сделать источником данных построителя запроса и наложить любые отборы!!!!
корум; VitaliyCeban; blindcat2006; Vlad_2008; wazup666; +5 Ответить
11. rabid_otter 134 17.05.20 21:21 Сейчас в теме
Для Каждого СтрТЗ Из ТЗ Цикл
Если Вычислить(Выражение) Тогда

ну такое...

(10) плюсую.
22. aspirator23 342 18.05.20 12:04 Сейчас в теме
(10) При том что почти во всех типовых конфигурациях есть в БСП функция на построителе для таких отборов. И работает очень быстро - мне даже кажется быстрее самодельного запроса.
30. Sergafan10 21.05.20 15:43 Сейчас в теме
(22) не подскажете адрес такой функции. Поискал в БСП 3.0.1.19 - не нашёл. Может плохо искал?
12. acanta 17.05.20 21:50 Сейчас в теме
В случае дробления периодов имхо перебор не самое худшее решение. Мне попалась ситуация, в которой больше 15 полей в запросе из табличной части (табеля) выбивало программу.
Если построчно нет неявных запросов к базе, а только 2*2 то почему это должно быть проблемой?
15. ImHunter 341 18.05.20 09:59 Сейчас в теме
Вообще, появление таких способов - это недоработка 1С (кто бы сомневался;). Ведь есть платформенный объект СравнениеЗначений. Почему бы не расширить функционал этого объекта, чтобы писать свой код сравнения... И почему бы не использовать такие объекты при сортировках и фильтрах...
21. Goleff74 218 18.05.20 10:49 Сейчас в теме
Для коллекции значений смысл имеет на клиенте. Для ТЗ - такое.
23. Darklight 37 18.05.20 14:18 Сейчас в теме
Жесть - ну вы даёте - для того чтобы применить несколько условий соединённых операцией "И"- Вы устраиваете перебор всей таблицы, пускай и каждый раз сокращающейся (и то не факт) после применения каждого условия.Это даже не стрельба из пушки - это стрельба из пулемёта типа "Миниган" по воробьям. Да ещё и с применением функции Вычислить - со всеми её недостатками и ограничениями (главный из них - отсутствие поддержки в iOS и требование небезопасного режима выполнения от сеанса), не говоря уже о снижении производительности в многократном циклическом вызове!

Ну ладно бы ещё - ожидать действительно правильной динамической реализации функционального подхода - когда код-реализация алгоритма перебора и фильтрации сначала генерируется целиком (с одним циклом перебора) - а потом уже выполняется единой инструкцией "Выполнить" (ах да - для web-клиента это не возможно... а какой тут нафиг WEB-Клиент - он таблицы значений вообще не поддерживает; но если сделать поддержку для клиентской коллекции ДанныеФормы, то для неё придётся сделать отдельную ветку алгоритма с циклическим (одним циклом) вызовов проверки условий через "Вычислить") - но это снижение производительности только для WEB-Клиента будет, не так уж часто используемого на практике).

Ну, а то, что если уже делать такую функцию - то надо сделать поодержку и других коллекций "ДеревоЗначений", "СписокЗначений", "Структура", "Соответствие", "Массив" (для последние коллекций имеется в виду, что фильтр будет на Значение, которое может содержать какое-то составное значение - например Структуру).

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

Ну а если уж так надо сделать более сложные условия (что бывает нужно не так уж часто) - то лучше воспользоваться механизмом СКД (именно СКД - т.к. тут и по таблицам значений (а остальные коллекции нужно будет к ней приводить) можно строить сложные условия, причём в этом случае обращения к СУБД не будет - одна беда - тонкий клиент(ы) не поддерживается). Ну и выгрузка результат в ТЗ из СКД выполняется типовым процессором вывода.

Вот такую универсальную функцию-обёртку было бы хорошо сделать и опубликовать!

Но это - сугубо моё личное мнение....
24. ImHunter 341 18.05.20 14:31 Сейчас в теме
(23) Ну... Можно много рассуждать на темы если бы да кабы.
А вот чел взял да и сделал.
26. Darklight 37 18.05.20 14:58 Сейчас в теме
(24)Ну можно много чего взять и сделать, был бы практический смысл. Я просто высказал, своё мнение, не более того
25. independ 1534 18.05.20 14:39 Сейчас в теме
27. Sergafan10 19.05.20 10:26 Сейчас в теме
Функция ОтборВТЗПоУсловию(ТЗ, ТЗОтборов) Экспорт
	
	Построитель = Новый ПостроительЗапроса;
	Построитель.ИсточникДанных = Новый ОписаниеИсточникаДанных(ТЗ);

	Для Каждого х ИЗ ТЗОтборов Цикл
		Отбор = Построитель.Отбор.Добавить(х.НаименованиеОтбора);//Наименование колонки, по которой будет отбор
		Отбор.ВидСравнения = ВидСравнения[х.ВидСравненияОтбора];//"Больше", "Равно", и тд
		Отбор.Значение = х.ЗначениеОтбора;
		Отбор.Использование = Истина;   		
	КонецЦикла;

	Построитель.Выполнить();
	
	Возврат Построитель.Результат.Выгрузить();
	
КонецФункции
Показать
ImHunter; Vlad_2008; Darklight; +3 Ответить
28. aspirator23 342 21.05.20 09:31 Сейчас в теме
(27) см (22) У них универсальнее
29. Sergafan10 21.05.20 15:42 Сейчас в теме
(28) где? что? не поленился, поискал в БСП 3.0.1.19 (не крайняя, конечно, но и не хлам), такую функцию. Так вот, там только одно упоминание о построителе запроса, в обработке сравнения табличных документов.
31. aspirator23 342 21.05.20 15:48 Сейчас в теме
(29) вот эта функция. Типовая, но насчет БСП - это я погорячился
// Отбирает из переданной таблицы строки по заданным критериям.
//
// Параметры:
//  Источник - ТаблицаЗначений, РезультатЗапроса, ОбластьЯчеекТабличногоДокумента - таблица-источник.
//  СтруктураКритериев - Структура - названия отборов и значения, по которым нужно отобрать строки.
//  СтруктураСложныхКритериев - Структура - если свойство передано, то значение содержит вид сравнения.
//
// Возвращаемое значение:
//  РезультатЗапроса - таблица с нужными строками.
//
Функция ОтобратьСтрокиПоКритериям(Источник, СтруктураКритериев, СтруктураСложныхКритериев = Неопределено) Экспорт

	Перем ВидСравненияСложный;

	Если СтруктураСложныхКритериев = Неопределено Тогда
		СтруктураСложныхКритериев = Новый Структура;
	КонецЕсли;

	ПостроительЗапроса = Новый ПостроительЗапроса;
	ПостроительЗапроса.ИсточникДанных = Новый ОписаниеИсточникаДанных(Источник);

	Для Каждого Критерий Из СтруктураКритериев Цикл
		НовыйОтбор = ПостроительЗапроса.Отбор.Добавить(Критерий.Ключ);

		СтруктураСложныхКритериев.Свойство(Критерий.Ключ, ВидСравненияСложный);

		Если ВидСравненияСложный = Неопределено Тогда
			НовыйОтбор.Установить(Критерий.Значение);
		Иначе
			НовыйОтбор.Использование = Истина;
			НовыйОтбор.ВидСравнения = ВидСравненияСложный;
			НовыйОтбор.Значение = Критерий.Значение;
		КонецЕсли;
	КонецЦикла;

	Возврат ПостроительЗапроса.Результат;

КонецФункции // ОтобратьСтрокиПоКритериям()
Показать
33. Cyberhawk 137 28.06.20 15:25 Сейчас в теме
(31)
ОтобратьСтрокиПоКритериям
В какой конфигурации такое есть?
34. aspirator23 342 28.06.20 20:38 Сейчас в теме
(33) В нескольких, где есть оперативный учет, встречал. Например: УПП, УТ 10, розницах старой и новой...
32. МихаилМ 23.05.20 21:35 Сейчас в теме
Знач ТЗ неправильно сильно
Для отправки сообщения требуется регистрация/авторизация