Как в 1С объединить сотрудников с одинаковыми должностями в одну строку?

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

При формировании печатных форм, отчетов или уведомлений часто возникает задача сгруппировать данные по определенному признаку. Одной из типичных задач является вывод списка сотрудников, где вместо повторения должности для каждого человека, мы выводим название должности один раз, а через запятую перечисляем всех сотрудников, которые её занимают. Например: «Продавец: Иванов И.И., Петров П.П.».

В этой статье мы подробно разберем, как реализовать такой механизм в коде 1С, проанализируем различные подходы и выберем наиболее эффективные методы работы с таблицами значений и строками.

Разбор базового алгоритма решения

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

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

Рассмотрим пошагово реализацию этого алгоритма:

  1. Создание списка уникальных должностей. Для этого мы копируем нужную колонку из основной таблицы и используем метод Свернуть.
  2. Обход должностей в цикле. Для каждой уникальной должности мы будем искать всех относящихся к ней сотрудников.
  3. Сбор сотрудников. Вложенным циклом мы обходим найденные строки и склеиваем фамилии в одну подстроку.
  4. Формирование финального текста. Добавляем полученную строку к общему результату, разделяя блоки переносом строки.

Вариант 1: Использование методов Таблицы Значений (Свернуть и НайтиСтроки)

Этот метод наиболее нагляден и прост в отладке. Рассмотрим пример кода, который реализует данную логику:


// 1. Получаем список уникальных должностей
СписокДолжностей = КадровыеДанные.Скопировать(, "ТекущаяДолжность");
СписокДолжностей.Свернуть("ТекущаяДолжность");

ИтоговыйТекст = "";

// 2. Основной цикл по должностям
Для Каждого СтрокаДолжности Из СписокДолжностей Цикл
    
    ТекущаяДолжность = СтрокаДолжности.ТекущаяДолжность;
    Отбор = Новый Структура("ТекущаяДолжность", ТекущаяДолжность);
    
    // Находим всех сотрудников для данной должности
    МассивСотрудников = КадровыеДанные.НайтиСтроки(Отбор);
    
    СотрудникиСтрокой = "";
    Счетчик = 1;
    
    // 3. Вложенный цикл для сбора ФИО
    Для Каждого СтрокаСотр Из МассивСотрудников Цикл
        
        // Получаем краткое ФИО (Иванов И.И.)
        ФИО = ФизическиеЛицаКлиентСервер.ФамилияИнициалы(СтрокаСотр.Сотрудник.Наименование);
        
        // Добавляем запятую, если это не последний сотрудник в списке
        Разделитель = ?(Счетчик = МассивСотрудников.Количество(), "", ", ");
        СотрудникиСтрокой = СотрудникиСтрокой + ФИО + Разделитель;
        
        Счетчик = Счетчик + 1;
    КонецЦикла;
    
    // 4. Формируем строку вида "-Должность: Сотрудник1, Сотрудник2"
    НоваяСтрока = "-" + ТекущаяДолжность + ": " + СотрудникиСтрокой;
    
    // Добавляем перенос строки, если текст уже не пустой
    ИтоговыйТекст = ИтоговыйТекст + ?(ПустаяСтрока(ИтоговыйТекст), "", Символы.ПС) + НоваяСтрока;

КонецЦикла;

Проанализируем этот код. Мы использовали конструкцию ?(Счетчик = МассивСотрудников.Количество(), "", ", "), чтобы красиво расставить запятые между фамилиями. Также важно обратить внимание на переменную ИтоговыйТекст: мы инициализируем её до цикла, а внутри цикла только дополняем. Это позволяет избежать потери данных при каждой новой итерации.

Вариант 2: Оптимизированный подход с использованием СтрСоединить

В современной платформе 1С:Предприятие 8.3 (начиная с версии 8.3.6) появилась замечательная функция СтрСоединить. Она позволяет объединить элементы массива в одну строку с заданным разделителем за одно действие. Это избавляет нас от необходимости использовать счетчики внутри цикла.

Разберем, как переписать наш алгоритм более лаконично:


СписокДолжностей = КадровыеДанные.Скопировать(, "ТекущаяДолжность");
СписокДолжностей.Свернуть("ТекущаяДолжность");

МассивСтрокВывода = Новый Массив;

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

КонецЦикла;

// Соединяем все должности через перенос строки
ИтоговыйРезультат = СтрСоединить(МассивСтрокВывода, Символы.ПС);

Использование массивов и функции СтрСоединить считается «хорошим тоном» в программировании на 1С. Это не только делает код чище, но и работает быстрее на больших объемах данных, так как платформа оптимизирует конкатенацию строк.

Вариант 3: Группировка через Соответствие (Map) для высокой производительности

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

Идея заключается в том, чтобы пройти по таблице сотрудников всего один раз, сразу распределяя их по «корзинам» (должностям).


// Ключ - Должность, Значение - Массив ФИО сотрудников
Группировка = Новый Соответствие;

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

// Теперь собираем финальный текст
ИтоговыйТекст = "";
Для Каждого Элемент Из Группировка Цикл
    Должность = Элемент.Ключ;
    Сотрудники = СтрСоединить(Элемент.Значение, ", ");
    
    ИтоговыйТекст = ИтоговыйТекст + "-" + Должность + ": " + Сотрудники + Символы.ПС;
КонецЦикла;

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

Полезные советы при работе с должностями

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

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

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

← На главную