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