В практике разработчика 1С часто возникает задача преобразования структуры данных, когда несколько строк, относящихся к одному объекту (например, сотруднику или номенклатуре), нужно «схлопнуть» в одну. При этом числовые показатели обычно суммируются, а текстовые — должны быть перечислены через запятую или другой разделитель. Рассмотрим подробно, как реализовать такое объединение различными способами: от использования Системы компоновки данных (СКД) до оптимизированного программного кода.
Если ваша задача — вывести данные в отчет, то использование Системы компоновки данных является наиболее эффективным и быстрым способом. Платформа 1С предоставляет встроенные агрегатные функции, которые позволяют манипулировать массивами строк прямо в ресурсах.
Разберем по шагам, как настроить такое объединение в СКД:
Сотрудник и Время.ТвойМассив. В колонке «Выражение» укажем: Массив(Время). Это преобразует все строковые значения времени для каждой группировки в коллекцию.ТвойМассив (или само поле Время) и в выражении напишем:
СоединитьСтроки(Массив(Время), ", ")
Сотрудник и в выбранные поля добавим наш ресурс.Важный нюанс: функция СоединитьСтроки поддерживает дополнительные параметры. Например, если вы хотите исключить дублирующиеся записи времени, в выражении ресурса можно использовать конструкцию ВЫБРАТЬ РАЗЛИЧНЫЕ. Также можно задать текст, который будет выводиться, если значений нет: СоединитьСтроки(Массив(Время), "; ", "Нет данных").
Если объединение необходимо выполнить непосредственно в объекте ТаблицаЗначений для дальнейшей программной обработки, рассмотрим алгоритм с предварительной сортировкой. Часто новички используют метод НайтиСтроки() внутри цикла, что на больших таблицах приводит к серьезным задержкам (сложность $O(n^2)$). Мы же применим метод линейного обхода.
Рассмотрим пример кода, который эффективно решает задачу за один проход:
// 1. Сортируем исходную таблицу по ключевому полю
ТЗ_Исходная.Сортировать("Сотрудник");
// 2. Создаем новую таблицу для результата
ТЗ_Результат = ТЗ_Исходная.СкопироватьКолонки();
// 3. Организуем обход
ТекущийСотрудник = Неопределено;
НоваяСтрока = Неопределено;
Для Каждого Стр Из ТЗ_Исходная Цикл
Если Стр.Сотрудник <> ТекущийСотрудник Тогда
// Нашли нового сотрудника - создаем строку в итоговой ТЗ
НоваяСтрока = ТЗ_Результат.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, Стр);
ТекущийСотрудник = Стр.Сотрудник;
Иначе
// Тот же сотрудник - дописываем время через разделитель
НоваяСтрока.Время = НоваяСтрока.Время + ", " + Стр.Время;
КонецЕсли;
КонецЦикла;
Этот метод работает максимально быстро, так как мы проходим по таблице всего один раз. Предварительная сортировка гарантирует, что все строки одного сотрудника идут друг за другом.
Проанализируем ситуацию, когда нам нужно использовать стандартный метод Свернуть(). Проблема в том, что метод Свернуть() умеет только суммировать числа, а строковые колонки он просто группирует, оставляя значение первой встретившейся строки.
Для реализации этого способа выполним следующие шаги:
ТЗ_Свернутая.Свернуть("Сотрудник"). Теперь у нас есть список уникальных сотрудников.Время (если она не была ключевой).Внимание: для ускорения этого процесса обязательно используйте Индексацию. Перед началом цикла добавьте индекс по полю поиска:
ТЗ_Исходная.Индексы.Добавить("Сотрудник");
// Теперь метод НайтиСтроки() будет работать в разы быстрее
Выясним причину, почему иногда лучше использовать СписокЗначений вместо прямой конкатенации строк. Прямое сложение строк через + в длинных циклах может быть затратным по памяти. Кроме того, СписокЗначений позволяет легко контролировать уникальность добавляемых элементов.
Посмотрим на пример логики:
Время храним не строку, а объект СписокЗначений.СтрокаИтог.Время.Добавить(Стр.Время).ВыгрузитьЗначения() и функцию СтрСоединить().Проанализируем важные моменты, которые могут повлиять на стабильность системы:
СтроковыеФункцииКлиентСервер.РазвернутьСтрокуИзМассива() для корректной склейки строк без лишних пробелов и пустых значений.Подводя итог, можно сказать: если цель — визуализация, выбирайте СКД с функцией СоединитьСтроки. Если данные нужны для алгоритмов — используйте программный обход с предварительной сортировкой. Это обеспечит и читаемость кода, и высокую скорость работы приложения.