Переход в среду 1С:Предприятие из языков классического программирования, таких как Pascal или C++, часто сопровождается трудностями в понимании работы с коллекциями и объектной моделью данных. Одной из типичных задач для начинающего разработчика является группировка данных: например, когда нужно из плоского списка реализаций получить итоги по каждому товару в разрезе различных способов оплаты (наличные, безналичные, сертификаты).
В этой статье мы подробно разберем, почему использование массивов и соответствий для этих целей может быть избыточным, как избежать ошибок при сравнении типов данных и почему ТаблицаЗначений является «золотым стандартом» для манипуляции данными в памяти.
Рассмотрим ситуацию: у нас есть табличная часть или список строк с данными о продажах. Мы хотим собрать суммы по каждому товару. Первое интуитивное решение программиста — создать Массив, внутри которого будут лежать объекты Соответствие (или Структура), где ключом будет имя поля, а значением — сумма.
Разберем, какие сложности возникают при таком подходе:
СправочникСсылка.Товары), а не просто строками. Сравнение ссылки со строкой всегда будет давать результат Ложь.В 1С существует объект ТаблицаЗначений, который идеально подходит для решения задач группировки. Проанализируем самый эффективный алгоритм, предложенный экспертами сообщества. Вместо ручного поиска в цикле, мы сначала наполняем таблицу всеми данными, а затем «схлопываем» её одним системным методом.
Рассмотрим реализацию пошагово:
// 1. Создаем служебную таблицу значений для итогов
ТипЧисло = Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2));
ТЗ_Итоги = Новый ТаблицаЗначений;
// Добавляем колонки. Колонки, по которым будем группировать (Товар)
// и колонки, которые будем суммировать (Суммы по типам оплаты)
ТЗ_Итоги.Колонки.Добавить("Товар");
ТЗ_Итоги.Колонки.Добавить("ИтогоСуммаНал", ТипЧисло);
ТЗ_Итоги.Колонки.Добавить("ИтогоСуммаБН", ТипЧисло);
ТЗ_Итоги.Колонки.Добавить("ИтогоСуммаПК", ТипЧисло);
// 2. Обходим исходные данные (например, из объектной коллекции Реализация)
Для Каждого Строка Из Объект.Реализация Цикл
НоваяСтрока = ТЗ_Итоги.Добавить();
НоваяСтрока.Товар = Строка.Товар; // Записываем ссылку на товар
// Распределяем сумму по нужным колонкам в зависимости от типа оплаты
// ВАЖНО: Сравниваем со значением Перечисления, а не со строкой!
Если Строка.ТипПлатежа = Перечисления.ТипыПлатежныхСредств.Наличные Тогда
НоваяСтрока.ИтогоСуммаНал = Строка.Итого;
ИначеЕсли Строка.ТипПлатежа = Перечисления.ТипыПлатежныхСредств.Безналичные Тогда
НоваяСтрока.ИтогоСуммаБН = Строка.Итого;
КонецЕсли;
КонецЦикла;
// 3. Магия 1С: группируем данные
// Первый параметр - колонки группировки, второй - колонки суммирования
ТЗ_Итоги.Свернуть("Товар", "ИтогоСуммаНал, ИтогоСуммаБН, ИтогоСуммаПК");
Почему это работает лучше? Метод Свернуть() реализован на уровне платформы и оптимизирован для быстрой работы с памятью. Вам не нужно заботиться о проверке «есть ли уже такой товар в списке» — платформа сделает это за вас.
Одной из главных причин, по которой у автора вопроса «суммы оставались нулевыми», было неправильное сравнение типов. В 1С ТипПлатежа — это обычно ПеречислениеСсылка.
Проанализируем типичную ошибку:
Если Строка.ТипПлатежа = "Наличные" Тогда — это условие никогда не выполнится, так как слева у нас сложный объект (ссылка), а справа — строка. Программа просто «пролетает» мимо всех условий суммирования.
Правильный способ сравнения:
Нужно обращаться к метаданным перечисления через глобальный контекст:
Если Строка.ТипПлатежа = Перечисления.ТипыОплаты.Наличные Тогда
// Код обработки
КонецЕсли;
Если же вы не знаете точное имя перечисления, используйте Отладчик. Остановите выполнение программы на строке с условием и посмотрите тип переменной Строка.ТипПлатежа в табло.
Хотя ТаблицаЗначений удобнее для вывода данных, иногда для промежуточных расчетов полезно использовать Соответствие. Это аналог Dictionary или HashMap. В отличие от структуры, ключом в соответствии может быть сама Ссылка на товар.
Разберем алгоритм «в один проход»:
ИтогиПоТоварам = Новый Соответствие; // Ключ - ТоварСсылка, Значение - Структура с суммами
Для Каждого Строка Из Объект.Реализация Цикл
ДанныеТовара = ИтогиПоТоварам.Получить(Строка.Товар);
Если ДанныеТовара = Неопределено Тогда
// Товар встретился впервые, инициализируем структуру
ДанныеТовара = Новый Структура("Нал, БН", 0, 0);
КонецЕсли;
// Накапливаем суммы
Если Строка.ТипПлатежа = Перечисления.ТипыОплаты.Наличные Тогда
ДанныеТовара.Нал = ДанныеТовара.Нал + Строка.Итого;
ИначеЕсли Строка.ТипПлатежа = Перечисления.ТипыОплаты.Безналичные Тогда
ДанныеТовара.БН = ДанныеТовара.БН + Строка.Итого;
КонецЕсли;
// Сохраняем обратно в соответствие
ИтогиПоТоварам.Вставить(Строка.Товар, ДанныеТовара);
КонецЦикла;
Этот метод эффективнее ручного перебора массива, так как поиск в Соответствии по ключу происходит мгновенно (хеш-таблица).
Чтобы лучше понимать, какой инструмент выбрать, проанализируем основные различия между коллекциями 1С:
Параметры.Сумма.Если ваш код не выдает ошибку, но результат (суммы) равен нулю, воспользуйтесь следующими советами:
Если и проверьте, заходит ли туда алгоритм.ТипЗнч(Строка.ТипПлатежа).Ctrl + F1 на методах вроде Свернуть или НайтиСтроки. Там всегда есть подробное описание и примеры.Использование правильных коллекций и понимание ссылочной природы данных в 1С превращает громоздкий «паскалеподобный» код в элегантные и быстрые решения на встроенном языке 1С.