Как объединить строки через запятую при сворачивании таблицы значений в 1С?

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

В практике разработчика 1С часто возникает задача агрегации данных. Типичный пример: имеется таблица значений с колонками Документ, Контрагент и НомерВагона. При использовании стандартного метода Свернуть() по колонкам Док и Контрагент, система оставляет в колонке НомерВагона лишь первое попавшееся значение, удаляя остальные. Наша задача — сделать так, чтобы номера вагонов не пропадали, а собирались в одну строку через запятую.

В этой статье мы подробно разберем несколько способов решения данной задачи: от самого простого программного перебора до использования возможностей Системы компоновки данных (СКД) и современных функций платформы 8.3.

Способ 1: Программный обход с использованием метода НайтиСтроки

Этот метод был предложен и успешно реализован автором темы. Он отлично подходит для небольших таблиц значений и понятен даже начинающему разработчику. Разберем алгоритм по шагам:

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

Рассмотрим программный код, реализующий этот подход:


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

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

Важный нюанс: В коде автора использовалась конструкция Лев(), однако более элегантным и надежным способом является проверка на пустую строку или использование современных функций платформы, которые мы рассмотрим далее.

Способ 2: Оптимизация через Индексы и Соответствие

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

Во-первых, перед началом цикла обязательно добавьте индекс по колонке, по которой производите поиск. Это значительно сократит время поиска:

ТЗ.Индексы.Добавить("Док");

Во-вторых, мы можем использовать объект Соответствие для сбора данных за один проход по таблице. Это наиболее производительный метод для больших объемов данных.

Разберем логику:

  1. Проходим по исходной таблице один раз.
  2. Используем Док как ключ соответствия, а значением будет Массив номеров вагонов.
  3. Если ключа в соответствии еще нет — создаем новый массив, если есть — добавляем номер в существующий.
  4. Затем создаем итоговую таблицу и заполняем её данными из соответствия.

Способ 3: Использование СтрСоединить (для платформы 8.3.10 и выше)

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

Пример использования совместно с массивом:


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

Этот подход делает код чище и снижает вероятность ошибок при обработке строковых разделителей.

Способ 4: Использование Системы компоновки данных (СКД)

Проанализируем ситуацию, когда данные нужны для отчета. В этом случае писать программный перебор таблиц вовсе не обязательно. СКД умеет агрегировать строки "из коробки".

Для этого выполним следующие действия:

  1. Добавим наш запрос в набор данных СКД.
  2. Перейдем на закладку "Ресурсы".
  3. Для поля НомерВагона в колонке "Выражение" напишем: СоединитьСтроки(ВычислитьВыражениеТаблица("НомерВагона"), ", ").
  4. Настроим группировку в отчете по полям Док и Контрагент.

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

Способ 5: Выгрузка в ДеревоЗначений

Если вам нужно отобразить данные на форме с возможностью раскрытия списка, рассмотрим вариант выгрузки результата запроса в ДеревоЗначений. В самом запросе можно настроить итоги:


ИТОГИ ПО
    Док,
    Контрагент

При обходе результата такого запроса методом Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам), вы получите иерархическую структуру. На уровне группировки вы сможете программно обойти детальные записи и сформировать нужную строку, не используя тяжеловесный метод НайтиСтроки.

Полезный совет: Если в исходных данных возможны дубли (например, один и тот же вагон указан в документе дважды), перед объединением в строку добавьте значения в Соответствие или используйте массив с предварительной проверкой на уникальность. Это сделает ваш отчет более профессиональным и читаемым.

← На главную