При разработке внешних обработок и алгоритмов обработки данных перед начинающими разработчиками часто встают две типовые задачи: подсчитать итоговую сумму по числовой колонке и удалить строки, удовлетворяющие определенному условию (например, по значению единицы измерения). Разберем типичные ошибки, возникающие при реализации этих задач, и рассмотрим правильные варианты решений.
Проанализируем базовый метод расчета итога для объекта ТаблицаЗначений. Для этого в платформе 1С предусмотрен встроенный метод Итог(). Посмотрим на синтаксис его вызова:
ИтоговаяСумма = ТаблицаТовары.Итог("Сумма");
При выполнении этого метода важно учитывать несколько ключевых правил:
Число). Если колонка содержит строки или другие типы, подсчет итога вызовет ошибку или вернет ноль.ДанныеФормыКоллекция, у которой нет метода Итог(). В таком случае на сервере необходимо выполнить преобразование коллекции в полноценную таблицу значений:
Таблица = ДанныеФормыВЗначение(Объект.Товары, Тип("ТаблицаЗначений"));
ИтоговаяСумма = Таблица.Итог("Сумма");
Если мы рассчитали сумму и хотим отобразить ее в нижней части таблицы (в подвале), выполним следующие настройки формы:
Истина. После этого под строками появится область подвала.ИтогСумма с типом Число), а в свойствах нужной колонки таблицы в поле ПутьКДаннымПодвала выберем этот реквизит. При пересчете достаточно будет присваивать значение этому реквизиту.
Элементы.ТоварыСумма.ТекстПодвала = Формат(ИтоговаяСумма, "ЧДЦ=2; ЧГ=0");
Рассмотрим распространенную ошибку прямого обхода в цикле от первого элемента к последнему:
// ОШИБОЧНЫЙ ВАРИАНТ!
Для Н = 0 По Таблица.Количество() - 1 Цикл
Если Таблица[Н].ЕдиницаИзмерения = НужнаяСсылка Тогда
Таблица.Удалить(Таблица[Н]);
КонецЕсли;
КонецЦикла;
В чем заключается проблема? Когда мы удаляем строку из таблицы, все последующие строки смещаются вверх (их индексы уменьшаются на единицу). Счётчик цикла при этом переходит к следующему номеру индекса, из-за чего цикл просто перепрыгивает через строку, идущую сразу за удаленной. Кроме того, к концу цикла счетчик попытается обратиться по индексу, которого уже не существует в таблице.
Наиболее лаконичный и быстрый способ поиска строк — использование встроенного метода НайтиСтроки(). Разберем его реализацию:
// 1. Формируем структуру отбора
// Имя ключа должно точно совпадать с именем колонки таблицы
СтруктураОтбора = Новый Структура("ЕдиницаИзмерения", СсылкаШт);
// 2. Получаем массив найденных строк
МассивУдаляемыхСтрок = ТаблицаТовары.НайтиСтроки(СтруктураОтбора);
// 3. Удаляем строки в цикле из таблицы
Для Каждого СтрокаТЗ Из МассивУдаляемыхСтрок Цикл
ТаблицаТовары.Удалить(СтрокаТЗ);
КонецЦикла;
Важное замечание: Метод НайтиСтроки() выполняет строгое сравнение типов. Если колонка содержит ссылку на элемент справочника (СправочникСсылка), в структуру отбора необходимо передавать именно объектную ссылку, а не строковое значение типа "Шт".
Если условие фильтрации сложное или составное, и метод НайтиСтроки() не подходит, организуем обход таблицы с конца к началу с отрицательным шагом. При таком подходе удаление строки в конце никак не влияет на индексы еще не проверенных строк в начале:
Для Индекс = ТаблицаТовары.Количество() - 1 По 0 Шаг -1 Цикл
ТекущаяСтрока = ТаблицаТовары[Индекс];
// Проверяем условие (на сервере можно обращаться через точку)
Если ТекущаяСтрока.ЕдиницаИзмерения.Наименование = "Шт" Тогда
ТаблицаТовары.Удалить(Индекс);
КонецЕсли;
КонецЦикла;
Когда таблица содержит тысячи строк, последовательное удаление элементов через методы таблицы может работать медленно из-за постоянного перестроения памяти. Разберем эффективный подход с использованием временных таблиц в объекте Запрос:
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
Запрос.Текст =
"ВЫБРАТЬ *
|ПОМЕСТИТЬ ВТ_Товары
|ИЗ &ТаблицаДанных КАК ТаблицаДанных;
|
|ВЫБРАТЬ *
|ИЗ ВТ_Товары
|ГДЕ ЕдиницаИзмерения <> &ИсключаемаяЕдиница";
Запрос.УстановитьПараметр("ТаблицаДанных", ИсходнаяТаблица);
Запрос.УстановитьПараметр("ИсключаемаяЕдиница", СсылкаШт);
ТаблицаТовары = Запрос.Выполнить().Выгрузить();
Этот вариант гарантирует высокую скорость обработки данных, исключает ошибки со смещением индексов и позволяет применять любые сложные логические условия в секции ГДЕ.