В процессе разработки на платформе 1С:Предприятие часто возникают задачи по манипуляции данными во временных структурах, таких как ТаблицаЗначений. Одной из типичных, но иногда вызывающих затруднение задач является очистка таблицы с сохранением лишь одной — последней — строки. На первый взгляд задача кажется тривиальной, однако при её реализации важно учитывать особенности работы платформы с памятью, жизненный цикл объектов типа СтрокаТаблицыЗначений и производительность системы при больших объемах данных.
В этой статье мы подробно разберем несколько подходов к решению этой задачи, проанализируем их эффективность и выясним, почему некоторые очевидные решения могут привести к ошибкам в коде.
Самый простой и интуитивно понятный способ — это последовательное удаление самой первой строки таблицы до тех пор, пока в ней не останется всего один элемент. Рассмотрим этот алгоритм подробнее.
Принцип работы: мы проверяем количество строк в таблице. Если оно больше единицы, мы удаляем строку с индексом 0. Платформа при этом автоматически сдвигает все последующие строки вверх, и бывшая вторая строка становится первой.
Пока ТЗ.Количество() > 1 Цикл
ТЗ.Удалить(0);
КонецЦикла;
Анализ ситуации: данный метод идеально подходит для таблиц с небольшим количеством строк (как в случае автора темы, где строк не более трех). Однако стоит помнить о производительности. При удалении первой строки (индекс 0) в большой таблице (например, 100 000 строк), платформа вынуждена 99 999 раз перемещать данные в памяти, чтобы заполнить образовавшуюся пустоту. Если ваша таблица велика, этот способ будет крайне медленным.
Чтобы избежать постоянного сдвига строк в памяти, эффективнее использовать удаление с конца таблицы. Мы оставим последнюю строку, а все остальные удалим, начиная с предпоследней и двигаясь к началу.
Разберем по шагам логику этого процесса:
ТЗ.Количество() - 1.ТЗ.Количество() - 2 (предпоследняя строка).
ВсегоСтрок = ТЗ.Количество();
Для Индекс = ВсегоСтрок - 2 По 0 Шаг -1 Цикл
ТЗ.Удалить(Индекс);
КонецЦикла;
Почему это быстрее? При удалении строки, за которой нет других данных (в данном случае мы удаляем строки «с хвоста»), системе не нужно пересчитывать индексы и сдвигать оставшиеся элементы. Хотя мы оставляем самую последнюю строку, технически удаление элементов перед ней с конца все равно эффективнее, чем постоянное удаление нулевого индекса.
Платформа 1С предоставляет мощный инструмент для работы с подмножествами строк — метод Скопировать(). Это, пожалуй, самый «красивый» и быстрый способ с точки зрения использования встроенных функций платформы.
Проанализируем пример кода:
МассивСтрТЗ = Новый Массив;
Если ТЗ.Количество() > 0 Тогда
МассивСтрТЗ.Добавить(ТЗ[ТЗ.Количество() - 1]);
ТЗ = ТЗ.Скопировать(МассивСтрТЗ);
КонецЕсли;
Важные нюансы:
Скопировать() создает новый объект таблицы значений. Если переменная ТЗ является реквизитом формы или параметром, переданным «по значению», вы можете потерять связь с исходным объектом.ТаблицаЗначений (например, на него завязаны элементы управления на форме), то после копирования следует очистить исходную таблицу и загрузить в неё строку из копии.Выясним причину, по которой нельзя просто написать Стр = ТЗ[Последняя]; ТЗ.Очистить(); ТЗ.Добавить(Стр);. Объект типа СтрокаТаблицыЗначений жестко связан со своим владельцем. Как только вызывается метод Очистить(), строка уничтожается в памяти, и ссылка на неё становится недействительной.
Поэтому правильным подходом будет сохранение значений колонок в промежуточный контейнер, который не зависит от таблицы (например, в структуру), очистка таблицы и создание новой строки.
Рассмотрим подробный пример реализации:
Если ТЗ.Количество() > 0 Тогда
// 1. Получаем последнюю строку
ПоследняяСтрока = ТЗ[ТЗ.Количество() - 1];
// 2. Копируем данные в структуру
ДанныеСтроки = Новый Структура;
Для Каждого Колонка Из ТЗ.Колонки Цикл
ДанныеСтроки.Вставить(Колонка.Имя, ПоследняяСтрока[Колонка.Имя]);
КонецЦикла;
// 3. Очищаем таблицу - это происходит мгновенно
ТЗ.Очистить();
// 4. Добавляем новую строку и заполняем её данными
НоваяСтрока = ТЗ.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, ДанныеСтроки);
КонецЕсли;
Этот метод сочетает в себе высокую скорость (метод Очистить() работает значительно быстрее удаления строк по одной) и надежность, так как мы не создаем новую таблицу значений, а работаем в рамках существующего объекта.
Выбор конкретного метода зависит от контекста вашей задачи:
Пока ТЗ.Количество() > 1. Это самый простой код, понятный любому разработчику.Структурой или Скопировать(). Это сэкономит время выполнения программного кода и ресурсы сервера.Мы рассмотрели основные способы манипуляции строками ТаблицыЗначений. Надеемся, что этот разбор поможет вам избежать «зависаний» при решении подобных задач и писать оптимальный, отказоустойчивый код.