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

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

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

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

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

Разберем по шагам, как настроить такое объединение в СКД:

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

Важный нюанс: функция СоединитьСтроки поддерживает дополнительные параметры. Например, если вы хотите исключить дублирующиеся записи времени, в выражении ресурса можно использовать конструкцию ВЫБРАТЬ РАЗЛИЧНЫЕ. Также можно задать текст, который будет выводиться, если значений нет: СоединитьСтроки(Массив(Время), "; ", "Нет данных").

Способ 2: Программный метод через линейный обход (оптимизированный)

Если объединение необходимо выполнить непосредственно в объекте ТаблицаЗначений для дальнейшей программной обработки, рассмотрим алгоритм с предварительной сортировкой. Часто новички используют метод НайтиСтроки() внутри цикла, что на больших таблицах приводит к серьезным задержкам (сложность $O(n^2)$). Мы же применим метод линейного обхода.

Рассмотрим пример кода, который эффективно решает задачу за один проход:


// 1. Сортируем исходную таблицу по ключевому полю
ТЗ_Исходная.Сортировать("Сотрудник");

// 2. Создаем новую таблицу для результата
ТЗ_Результат = ТЗ_Исходная.СкопироватьКолонки();

// 3. Организуем обход
ТекущийСотрудник = Неопределено;
НоваяСтрока = Неопределено;

Для Каждого Стр Из ТЗ_Исходная Цикл
    Если Стр.Сотрудник <> ТекущийСотрудник Тогда
        // Нашли нового сотрудника - создаем строку в итоговой ТЗ
        НоваяСтрока = ТЗ_Результат.Добавить();
        ЗаполнитьЗначенияСвойств(НоваяСтрока, Стр);
        ТекущийСотрудник = Стр.Сотрудник;
    Иначе
        // Тот же сотрудник - дописываем время через разделитель
        НоваяСтрока.Время = НоваяСтрока.Время + ", " + Стр.Время;
    КонецЕсли;
КонецЦикла;

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

Способ 3: Метод через «схлопывание» (Свернуть) и поиск

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

Для реализации этого способа выполним следующие шаги:

  1. Создадим копию исходной таблицы и применим к ней метод ТЗ_Свернутая.Свернуть("Сотрудник"). Теперь у нас есть список уникальных сотрудников.
  2. Добавим в свернутую таблицу колонку Время (если она не была ключевой).
  3. Обойдем свернутую таблицу и для каждого сотрудника найдем все его вхождения в исходной таблице, склеивая строки.

Внимание: для ускорения этого процесса обязательно используйте Индексацию. Перед началом цикла добавьте индекс по полю поиска:


ТЗ_Исходная.Индексы.Добавить("Сотрудник");
// Теперь метод НайтиСтроки() будет работать в разы быстрее

Способ 4: Использование СписокЗначений для сбора данных

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

Посмотрим на пример логики:

  1. В итоговой таблице значений в колонке Время храним не строку, а объект СписокЗначений.
  2. При обходе исходных данных находим нужную строку в итоговой ТЗ и добавляем значение в список: СтрокаИтог.Время.Добавить(Стр.Время).
  3. На этапе вывода данных (например, в печатную форму) используем метод списка ВыгрузитьЗначения() и функцию СтрСоединить().

Технические ограничения и нюансы

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

Подводя итог, можно сказать: если цель — визуализация, выбирайте СКД с функцией СоединитьСтроки. Если данные нужны для алгоритмов — используйте программный обход с предварительной сортировкой. Это обеспечит и читаемость кода, и высокую скорость работы приложения.

← На главную