В практике разработчика 1С часто возникает задача обработки коллекций данных, которые приходят из внешних источников или формируются динамически в коде. Одной из таких задач является фильтрация массива сотрудников по дате рождения и их последующее упорядочивание. Сложность заключается в том, что стандартный объект Массив в 1С не обладает встроенным методом Сортировать(), а фильтрация по частям даты (например, только по месяцу) требует понимания особенностей работы с типами данных.
В данной статье мы разберем несколько подходов к решению этой задачи: от простых переборов до использования мощных механизмов запросов и временных таблиц. Мы научимся правильно извлекать месяц, эффективно фильтровать данные и подготавливать их для вывода пользователю.
Прежде чем приступать к написанию кода, проанализируем структуру данных. Если на вход подается массив, то каждый его элемент обычно представляет собой объект типа Структура. В этой структуре содержатся ключи, например, Сотрудник (ссылка на справочник) и ДатаРождения (тип Дата).
Наша цель состоит из двух этапов:
ДатаРождения совпадает с месяцем текущей даты.Рассмотрим наиболее гибкий способ — преобразование массива в ТаблицаЗначений. Этот объект обладает мощными методами сортировки и поиска. Данный метод идеально подходит для работы на стороне сервера.
Разберем процесс по шагам. Сначала создадим таблицу, затем заполним ее данными из массива, выполним фильтрацию и, наконец, отсортируем результат.
// Предположим, МассивСотрудников — это наш входной массив структур
// 1. Создаем таблицу значений и описываем колонки
ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Сотрудник");
ТЗ.Колонки.Добавить("ДатаРождения", Новый ОписаниеТипов("Дата"));
ТЗ.Колонки.Добавить("ДеньРождения", Новый ОписаниеТипов("Число")); // Вспомогательная колонка для сортировки
ТекущийМесяц = Месяц(ТекущаяДатаСеанса());
// 2. Заполняем таблицу с фильтрацией
Для Каждого Элемент Из МассивСотрудников Цикл
Если Месяц(Элемент.ДатаРождения) = ТекущийМесяц Тогда
НоваяСтрока = ТЗ.Добавить();
НоваяСтрока.Сотрудник = Элемент.Сотрудник;
НоваяСтрока.ДатаРождения = Элемент.ДатаРождения;
// Записываем день месяца для корректной сортировки
НоваяСтрока.ДеньРождения = День(Элемент.ДатаРождения);
КонецЕсли;
КонецЦикла;
// 3. Сортируем таблицу по дню рождения
ТЗ.Сортировать("ДеньРождения Возр");
// 4. Выгружаем результат обратно в массив, если это необходимо
ИтоговыйМассив = ТЗ.ВыгрузитьКолонку("Сотрудник");
Обратим внимание на важный нюанс: мы добавили колонку ДеньРождения. Если сортировать просто по колонке ДатаРождения, 1С будет учитывать и год. В результате сотрудники, родившиеся 1-го числа 1980 года, окажутся в списке раньше, чем родившиеся 1-го числа 1990 года, что не всегда удобно для календаря праздников. Использование функции День() позволяет избежать этой проблемы.
Если задача должна быть решена на клиенте (в тонком или веб-клиенте), где объект ТаблицаЗначений недоступен, мы можем использовать СписокЗначений. Этот объект доступен везде и имеет встроенный метод СортироватьПоПредставлению() или СортироватьПоЗначению().
Проанализируем пример, где мы используем представление для хранения ключа сортировки:
Список = Новый СписокЗначений;
ТекущийМесяц = Месяц(ТекущаяДата());
Для Каждого Элемент Из МассивСотрудников Цикл
Если Месяц(Элемент.ДатаРождения) = ТекущийМесяц Тогда
// Формируем представление так, чтобы оно начиналось с дня (с ведущим нулем)
// Это позволит правильно отсортировать список по алфавиту
ПредставлениеДляСортировки = Формат(День(Элемент.ДатаРождения), "ЧЦ=2; ЧВН=") + " - " + Элемент.Сотрудник;
Список.Добавить(Элемент.Сотрудник, ПредставлениеДляСортировки);
КонецЕсли;
КонецЦикла;
// Сортируем список
Список.СортироватьПоПредставлению(НаправлениеСортировки.Возр);
В данном случае мы использовали функцию Формат() с параметром ЧВН= (выводить ведущие нули), чтобы день "5" превратился в "05". Это критически важно для корректной строковой сортировки, иначе "10" окажется раньше "2".
Если сотрудников очень много (тысячи), наиболее производительным методом будет использование механизма запросов. В 1С версии 8.3 можно передать массив во временную таблицу запроса. Это считается "золотым стандартом" для обеспечения высокой скорости работы системы.
Выясним причину эффективности этого метода: СУБД выполняет операции фильтрации и сортировки гораздо быстрее, чем программный перебор в цикле. Посмотрим на пример реализации:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ВТ_Сотрудники.Сотрудник КАК Сотрудник,
| ВТ_Сотрудники.ДатаРождения КАК ДатаРождения
|ПОМЕСТИТЬ ВременнаяТаблица
|ИЗ
| &ВходнойМассив КАК ВТ_Сотрудники
|;
|
|ВЫБРАТЬ
| Т.Сотрудник,
| Т.ДатаРождения
|ИЗ
| ВременнаяТаблица КАК Т
|ГДЕ
| МЕСЯЦ(Т.ДатаРождения) = МЕСЯЦ(&ТекущаяДата)
|УПОРЯДОЧИТЬ ПО
| ДЕНЬ(Т.ДатаРождения)";
Запрос.УстановитьПараметр("ВходнойМассив", МассивСотрудников);
Запрос.УстановитьПараметр("ТекущаяДата", ТекущаяДатаСеанса());
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
// Обработка отсортированных данных
КонецЦикла;
Важное замечание: Чтобы передать массив структур в запрос как таблицу, структура в массиве должна иметь строго одинаковый набор ключей, соответствующих именам полей в запросе.
Иногда возникают ситуации, когда использование дополнительных объектов коллекций нежелательно или требуется реализовать логику на чистом алгоритме. В таких случаях можно вспомнить классическую сортировку "пузырьком". Хотя она медленнее на больших массивах, для списка сотрудников одного подразделения ее вполне достаточно.
Разберем код реализации:
// Сначала фильтруем массив, создавая новый
МассивРезультат = Новый Массив;
ТекущийМесяц = Месяц(ТекущаяДата());
Для Каждого Элемент Из МассивСотрудников Цикл
Если Месяц(Элемент.ДатаРождения) = ТекущийМесяц Тогда
МассивРезультат.Добавить(Элемент);
КонецЕсли;
КонецЦикла;
// Теперь сортируем отфильтрованный массив пузырьком по дню рождения
Кол = МассивРезультат.Количество();
Для и = 0 По Кол - 2 Цикл
Для j = и + 1 По Кол - 1 Цикл
Если День(МассивРезультат[и].ДатаРождения) > День(МассивРезультат[j].ДатаРождения) Тогда
// Меняем элементы местами
Врем = МассивРезультат[и];
МассивРезультат[и] = МассивРезультат[j];
МассивРезультат[j] = Врем;
КонецЕсли;
КонецЦикла;
КонецЦикла;
Мы проанализировали различные подходы к фильтрации и сортировке массива в 1С. Подведем итоги выбора инструмента:
Помните, что при работе с датами крайне важно учитывать контекст выполнения кода (клиент или сервер) и использовать ТекущаяДатаСеанса() вместо ТекущаяДата() в распределенных системах для корректного определения текущего месяца.