Как отобрать сотрудников, родившихся в текущем месяце, из массива и отсортировать их?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

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

Анализ входных данных и постановка задачи

Прежде чем приступать к написанию кода, проанализируем структуру данных. Если на вход подается массив, то каждый его элемент обычно представляет собой объект типа Структура. В этой структуре содержатся ключи, например, Сотрудник (ссылка на справочник) и ДатаРождения (тип Дата).

Наша цель состоит из двух этапов:

  1. Фильтрация: Оставить только тех сотрудников, у которых месяц в поле ДатаРождения совпадает с месяцем текущей даты.
  2. Сортировка: Упорядочить полученный список. Чаще всего требуется сортировка по дню месяца, чтобы видеть ближайшие дни рождения, независимо от года рождения сотрудника.

Способ 1. Использование Таблицы Значений (Универсальный метод)

Рассмотрим наиболее гибкий способ — преобразование массива в ТаблицаЗначений. Этот объект обладает мощными методами сортировки и поиска. Данный метод идеально подходит для работы на стороне сервера.

Разберем процесс по шагам. Сначала создадим таблицу, затем заполним ее данными из массива, выполним фильтрацию и, наконец, отсортируем результат.


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

ТекущийМесяц = Месяц(ТекущаяДатаСеанса());

// 2. Заполняем таблицу с фильтрацией
Для Каждого Элемент Из МассивСотрудников Цикл
    Если Месяц(Элемент.ДатаРождения) = ТекущийМесяц Тогда
        НоваяСтрока = ТЗ.Добавить();
        НоваяСтрока.Сотрудник = Элемент.Сотрудник;
        НоваяСтрока.ДатаРождения = Элемент.ДатаРождения;
        // Записываем день месяца для корректной сортировки
        НоваяСтрока.ДеньРождения = День(Элемент.ДатаРождения);
    КонецЕсли;
КонецЦикла;

// 3. Сортируем таблицу по дню рождения
ТЗ.Сортировать("ДеньРождения Возр");

// 4. Выгружаем результат обратно в массив, если это необходимо
ИтоговыйМассив = ТЗ.ВыгрузитьКолонку("Сотрудник");

Обратим внимание на важный нюанс: мы добавили колонку ДеньРождения. Если сортировать просто по колонке ДатаРождения, 1С будет учитывать и год. В результате сотрудники, родившиеся 1-го числа 1980 года, окажутся в списке раньше, чем родившиеся 1-го числа 1990 года, что не всегда удобно для календаря праздников. Использование функции День() позволяет избежать этой проблемы.

Способ 2. Использование Списка Значений (Для клиентской стороны)

Если задача должна быть решена на клиенте (в тонком или веб-клиенте), где объект ТаблицаЗначений недоступен, мы можем использовать СписокЗначений. Этот объект доступен везде и имеет встроенный метод СортироватьПоПредставлению() или СортироватьПоЗначению().

Проанализируем пример, где мы используем представление для хранения ключа сортировки:


Список = Новый СписокЗначений;
ТекущийМесяц = Месяц(ТекущаяДата());

Для Каждого Элемент Из МассивСотрудников Цикл
    Если Месяц(Элемент.ДатаРождения) = ТекущийМесяц Тогда
        // Формируем представление так, чтобы оно начиналось с дня (с ведущим нулем)
        // Это позволит правильно отсортировать список по алфавиту
        ПредставлениеДляСортировки = Формат(День(Элемент.ДатаРождения), "ЧЦ=2; ЧВН=") + " - " + Элемент.Сотрудник;
        Список.Добавить(Элемент.Сотрудник, ПредставлениеДляСортировки);
    КонецЕсли;
КонецЦикла;

// Сортируем список
Список.СортироватьПоПредставлению(НаправлениеСортировки.Возр);

В данном случае мы использовали функцию Формат() с параметром ЧВН= (выводить ведущие нули), чтобы день "5" превратился в "05". Это критически важно для корректной строковой сортировки, иначе "10" окажется раньше "2".

Способ 3. Использование Запроса к внешним данным

Если сотрудников очень много (тысячи), наиболее производительным методом будет использование механизма запросов. В 1С версии 8.3 можно передать массив во временную таблицу запроса. Это считается "золотым стандартом" для обеспечения высокой скорости работы системы.

Выясним причину эффективности этого метода: СУБД выполняет операции фильтрации и сортировки гораздо быстрее, чем программный перебор в цикле. Посмотрим на пример реализации:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |    ВТ_Сотрудники.Сотрудник КАК Сотрудник,
    |    ВТ_Сотрудники.ДатаРождения КАК ДатаРождения
    |ПОМЕСТИТЬ ВременнаяТаблица
    |ИЗ
    |    &ВходнойМассив КАК ВТ_Сотрудники
    |;
    |
    |ВЫБРАТЬ
    |    Т.Сотрудник,
    |    Т.ДатаРождения
    |ИЗ
    |    ВременнаяТаблица КАК Т
    |ГДЕ
    |    МЕСЯЦ(Т.ДатаРождения) = МЕСЯЦ(&ТекущаяДата)
    |УПОРЯДОЧИТЬ ПО
    |    ДЕНЬ(Т.ДатаРождения)";

Запрос.УстановитьПараметр("ВходнойМассив", МассивСотрудников);
Запрос.УстановитьПараметр("ТекущаяДата", ТекущаяДатаСеанса());

РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();

Пока Выборка.Следующий() Цикл
    // Обработка отсортированных данных
КонецЦикла;

Важное замечание: Чтобы передать массив структур в запрос как таблицу, структура в массиве должна иметь строго одинаковый набор ключей, соответствующих именам полей в запросе.

Способ 4. Алгоритмическая сортировка (Метод пузырька)

Иногда возникают ситуации, когда использование дополнительных объектов коллекций нежелательно или требуется реализовать логику на чистом алгоритме. В таких случаях можно вспомнить классическую сортировку "пузырьком". Хотя она медленнее на больших массивах, для списка сотрудников одного подразделения ее вполне достаточно.

Разберем код реализации:


// Сначала фильтруем массив, создавая новый
МассивРезультат = Новый Массив;
ТекущийМесяц = Месяц(ТекущаяДата());

Для Каждого Элемент Из МассивСотрудников Цикл
    Если Месяц(Элемент.ДатаРождения) = ТекущийМесяц Тогда
        МассивРезультат.Добавить(Элемент);
    КонецЕсли;
КонецЦикла;

// Теперь сортируем отфильтрованный массив пузырьком по дню рождения
Кол = МассивРезультат.Количество();
Для и = 0 По Кол - 2 Цикл
    Для j = и + 1 По Кол - 1 Цикл
        Если День(МассивРезультат[и].ДатаРождения) > День(МассивРезультат[j].ДатаРождения) Тогда
            // Меняем элементы местами
            Врем = МассивРезультат[и];
            МассивРезультат[и] = МассивРезультат[j];
            МассивРезультат[j] = Врем;
        КонецЕсли;
    КонецЦикла;
КонецЦикла;

Подведение итогов

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

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

← На главную