Как сгруппировать данные по товарам и видам оплаты: от массивов к таблицам значений в 1С

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

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

В этой статье мы подробно разберем, почему использование массивов и соответствий для этих целей может быть избыточным, как избежать ошибок при сравнении типов данных и почему ТаблицаЗначений является «золотым стандартом» для манипуляции данными в памяти.

Анализ проблемы: почему массив соответствий — не лучший выбор

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

Разберем, какие сложности возникают при таком подходе:

  1. Сложность поиска: Чтобы обновить сумму существующего товара, нам приходится каждый раз в цикле перебирать весь массив, сравнивая товар в строке с товаром в массиве. Это операция с производительностью O(n^2), что крайне медленно при больших объемах данных.
  2. Типизация данных: В 1С значения в ячейках таблиц часто являются ссылками (например, СправочникСсылка.Товары), а не просто строками. Сравнение ссылки со строкой всегда будет давать результат Ложь.
  3. Избыточность кода: Написание ручных алгоритмов поиска и суммирования увеличивает риск ошибок и делает код трудночитаемым.

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

В 1С существует объект ТаблицаЗначений, который идеально подходит для решения задач группировки. Проанализируем самый эффективный алгоритм, предложенный экспертами сообщества. Вместо ручного поиска в цикле, мы сначала наполняем таблицу всеми данными, а затем «схлопываем» её одним системным методом.

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


// 1. Создаем служебную таблицу значений для итогов
ТипЧисло = Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2));
ТЗ_Итоги = Новый ТаблицаЗначений;

// Добавляем колонки. Колонки, по которым будем группировать (Товар) 
// и колонки, которые будем суммировать (Суммы по типам оплаты)
ТЗ_Итоги.Колонки.Добавить("Товар"); 
ТЗ_Итоги.Колонки.Добавить("ИтогоСуммаНал", ТипЧисло);
ТЗ_Итоги.Колонки.Добавить("ИтогоСуммаБН", ТипЧисло);
ТЗ_Итоги.Колонки.Добавить("ИтогоСуммаПК", ТипЧисло);

// 2. Обходим исходные данные (например, из объектной коллекции Реализация)
Для Каждого Строка Из Объект.Реализация Цикл
    НоваяСтрока = ТЗ_Итоги.Добавить();
    НоваяСтрока.Товар = Строка.Товар; // Записываем ссылку на товар
    
    // Распределяем сумму по нужным колонкам в зависимости от типа оплаты
    // ВАЖНО: Сравниваем со значением Перечисления, а не со строкой!
    Если Строка.ТипПлатежа = Перечисления.ТипыПлатежныхСредств.Наличные Тогда
        НоваяСтрока.ИтогоСуммаНал = Строка.Итого;
    ИначеЕсли Строка.ТипПлатежа = Перечисления.ТипыПлатежныхСредств.Безналичные Тогда
        НоваяСтрока.ИтогоСуммаБН = Строка.Итого;
    КонецЕсли;
КонецЦикла;

// 3. Магия 1С: группируем данные
// Первый параметр - колонки группировки, второй - колонки суммирования
ТЗ_Итоги.Свернуть("Товар", "ИтогоСуммаНал, ИтогоСуммаБН, ИтогоСуммаПК");

Почему это работает лучше? Метод Свернуть() реализован на уровне платформы и оптимизирован для быстрой работы с памятью. Вам не нужно заботиться о проверке «есть ли уже такой товар в списке» — платформа сделает это за вас.

Важный нюанс: Сравнение перечислений и ссылок

Одной из главных причин, по которой у автора вопроса «суммы оставались нулевыми», было неправильное сравнение типов. В 1С ТипПлатежа — это обычно ПеречислениеСсылка.

Проанализируем типичную ошибку:

Если Строка.ТипПлатежа = "Наличные" Тогда — это условие никогда не выполнится, так как слева у нас сложный объект (ссылка), а справа — строка. Программа просто «пролетает» мимо всех условий суммирования.

Правильный способ сравнения:

Нужно обращаться к метаданным перечисления через глобальный контекст:


Если Строка.ТипПлатежа = Перечисления.ТипыОплаты.Наличные Тогда
    // Код обработки
КонецЕсли;

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

Решение №2: Использование Соответствия для накопления итогов

Хотя ТаблицаЗначений удобнее для вывода данных, иногда для промежуточных расчетов полезно использовать Соответствие. Это аналог Dictionary или HashMap. В отличие от структуры, ключом в соответствии может быть сама Ссылка на товар.

Разберем алгоритм «в один проход»:


ИтогиПоТоварам = Новый Соответствие; // Ключ - ТоварСсылка, Значение - Структура с суммами

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

Этот метод эффективнее ручного перебора массива, так как поиск в Соответствии по ключу происходит мгновенно (хеш-таблица).

Справочная информация по коллекциям

Чтобы лучше понимать, какой инструмент выбрать, проанализируем основные различия между коллекциями 1С:

Рекомендации по отладке

Если ваш код не выдает ошибку, но результат (суммы) равен нулю, воспользуйтесь следующими советами:

  1. Точки останова: Поставьте точку останова на условии Если и проверьте, заходит ли туда алгоритм.
  2. Типы данных: В окне вычисления выражений проверьте ТипЗнч(Строка.ТипПлатежа).
  3. Синтаксис-помощник: Не забывайте нажимать Ctrl + F1 на методах вроде Свернуть или НайтиСтроки. Там всегда есть подробное описание и примеры.

Использование правильных коллекций и понимание ссылочной природы данных в 1С превращает громоздкий «паскалеподобный» код в элегантные и быстрые решения на встроенном языке 1С.

← На главную