В процессе разработки на платформе 1С часто возникает задача оптимизации данных, хранящихся в ТаблицаЗначений. Одной из типичных ситуаций является необходимость «схлопывания» строк: если значение в строке меньше заданного порога, мы хотим перенести это значение в другую строку, а саму исходную запись удалить, чтобы итоговая сумма по колонке осталась неизменной.
Давайте разберем, почему простой цикл Для Каждого здесь не подходит и какие методы являются наиболее надежными и профессиональными.
Основная проблема при использовании конструкции Для Каждого заключается в том, что коллекция (ТаблицаЗначений) модифицируется прямо во время обхода. Когда вы вызываете метод Удалить(), индексы оставшихся строк смещаются. Это приводит к тому, что цикл «перескакивает» через элементы, пропуская их, или обращается к несуществующим индексам, вызывая ошибки платформы. Для решения этой задачи мы рассмотрим два основных подхода.
Самый простой способ избежать проблем со смещением индексов — это обход таблицы в обратном порядке: от последнего элемента к первому. При таком подходе удаление строки с индексом N никак не влияет на индексы строк от 0 до N-1, которые нам еще предстоит обработать.
Рассмотрим реализацию на примере:
Индекс = ТаблицаЗначений.Количество() - 1;
Пока Индекс >= 0 Цикл
Если ТаблицаЗначений[Индекс].Число < 5 Тогда
// Переносим значение в предыдущую строку
ТаблицаЗначений[Индекс - 1].Число = ТаблицаЗначений[Индекс - 1].Число + ТаблицаЗначений[Индекс].Число;
ТаблицаЗначений.Удалить(Индекс);
Иначе
Индекс = Индекс - 1;
КонецЕсли;
КонецЦикла;
Важное примечание: При использовании этого метода необходимо следить за тем, чтобы Индекс - 1 не вышел за границы массива (т.е. не стал меньше нуля), иначе возникнет исключительная ситуация.
Этот метод считается более современным и понятным. Мы разделяем логику поиска строк и логику изменения данных. Сначала мы проходим по таблице, аккумулируем «лишние» значения в переменной, а строки, которые нужно удалить, собираем в отдельный Массив. Это позволяет избежать любых конфликтов с индексацией.
Разберем алгоритм по шагам:
ОсталосьЧасовНаПроект для накопления суммы удаляемых значений.Массив для хранения ссылок на строки, подлежащие удалению.ТЗ.Удалить().
ОсталосьЧасовНаПроект = 0;
МассивСтрокДляУдаления = Новый Массив;
Для Каждого Стр Из ТЗ Цикл
Если Стр.ЧасовНаПроект < 8 Тогда
ОсталосьЧасовНаПроект = ОсталосьЧасовНаПроект + Стр.ЧасовНаПроект;
МассивСтрокДляУдаления.Добавить(Стр);
ИначеЕсли ОсталосьЧасовНаПроект > 0 Тогда
Стр.ЧасовНаПроект = Стр.ЧасовНаПроект + ОсталосьЧасовНаПроект;
ОсталосьЧасовНаПроект = 0;
КонецЕсли;
КонецЦикла;
Для Каждого СтрУдалить Из МассивСтрокДляУдаления Цикл
ТЗ.Удалить(СтрУдалить);
КонецЦикла;
// Проверяем остаток после завершения цикла
Если ОсталосьЧасовНаПроект > 0 И ТЗ.Количество() > 0 Тогда
ТЗ[0].ЧасовНаПроект = ТЗ[0].ЧасовНаПроект + ОсталосьЧасовНаПроект;
КонецЕсли;
СвернутьЕсли ваша задача сводится к простому суммированию показателей по определенному ключу (например, по сотруднику или проекту), всегда анализируйте, нельзя ли применить метод ТаблицаЗначений.Свернуть(). Это штатный механизм 1С, который работает значительно быстрее любого ручного перебора циклом. Он автоматически суммирует числа и удаляет дублирующие строки, группируя данные по заданным колонкам.
Используя эти методы, вы сможете безопасно и эффективно манипулировать данными в ТаблицаЗначений, сохраняя целостность ваших расчетов.