Добрый вечер. Подскажите, что нужно сделать, чтобы удаление в таблице значений было корректным? Я методом Найти ищу сроку. Ее удаляю, но после первого удаления строки, строки меняются как то и удаляются или не все или не те.
---
Добрый день. Удалять надо так:

Сч = 0;
Пока (Сч < ТаблицаДанных.Количество ()) Цикл
     Строка = ТаблицаДанных.ПолучитьСтроку (Сч);
     Если (УдаляемСтроку (Строка)) Тогда
          ТаблицаДанных.Удалить(Сч);
     Иначе
          Сч = Сч + 1;
     КонецЕсли;
КонецЦикла;

где Функция УдаляемСтроку () - анализ строки на удаление. Работает правильно и быстро.
---
обходить таблицу надо с конца. А вы похоже с начала, вот индекс теряется!
---
Можно и не обходить. Автор-то не приводит свой код и не ясно что ему нужно. Лишь что-то ищет функцией Найти и удаляет. В этом случае обход может и не понадобится.

Вот куча способов удаление.

```1c
    // 1. Удаление строк согласно условию

    НулевыеСтроки = ТаблицаПослеПодмен.НайтиСтроки(Новый Структура("Сумма",0));

    Для каждого СтрокаТаблицы Из НулевыеСтроки Цикл

    ТаблицаПослеПодмен.Удалить(СтрокаТаблицы)

    КонецЦикла;

    // Нужно оставить строки только соответствующие условию,а остальные удалить то:

    ПараметрыОтбора = Новый Структура("Цена",15000);

    ТЗНов = ТЗ.Скопировать(ПараметрыОтбора);

    // в результате в ТЗнов будут только строки из ТЗ, в которых значение поля Цена = 15000

    // 2. Удаление определенной строки, например УдаляемаяСтрока = 5;

    ТаблицаЗначений.Удалить(УдаляемаяСтрока);

    // 3. Удаление первой строки

    ТаблицаЗначений.Удалить(0);

    // 4. Удаление определенной колонки, например УдаляемаяКолонка = 3;

    ТаблицаЗначений.Колонки.Удалить(УдаляемаяКолонка);

    // 5. Удалить первую колонку

    ТаблицаЗначений.Колонки.Удалить(0);

    // 6. Удаление строк перебором, проверяя условие

    СтаршийИндексКолонок = ТаблицаЗначений.Колонки.Количество() - 1;

    Индекс = ТаблицаЗначений.Количество() - 1;

    Пока Индекс > = 0 Цикл

    Для Сч = 0 По СтаршийИндексКолонок Цикл

    Если ТипЗнч(ТаблицаЗначений[Индекс][Сч]) = Тип("Число") Тогда

    ТаблицаЗначений.Удалить(Индекс);

    Прервать;

    КонецЕсли;

    КонецЦикла;

    Индекс = Индекс - 1;

    КонецЦикла;
```
---
Вообще-то проблема сформулирована крайне чётко, перечитайте вопрос... :)
---
Сообщение было скрыто модератором.
---
Добрый день. Удалять надо так:

Сч = 0;
Пока (Сч < ТаблицаДанных.Количество ()) Цикл
     Строка = ТаблицаДанных.ПолучитьСтроку (Сч);
     Если (УдаляемСтроку (Строка)) Тогда
          ТаблицаДанных.Удалить(Сч);
     Иначе
          Сч = Сч + 1;
     КонецЕсли;
КонецЦикла;

где Функция УдаляемСтроку () - анализ строки на удаление. Работает правильно и быстро.
---
Я всё таки предпочитаю удалять строки после полной обработки таблицы, и индексы не портятся и не нужно помнить нюансы каждого языка программирования :)
---
Ну, тогда можете так:

```1c
    ТаблицаДанных.Колонки.Добавить ("Удалить");
    Для Каждого ТекСтрока Из ТаблицаДанных Цикл
    ТекСтрока.Удалить = УдаляемСтроку (Строка);
    КонецЦикла;
    ОтборСтрок = Новый Структура ("Удалить", Истина);
    Строки = ТаблицаДанных.НайтиСтроки (ОтборСтрок );
    ТаблицаДанных.Колонки.Удалить("Удалить");
```

И теперь удаляйте строки в ТаблицаДанных из списка строк Строки

Хотя, это уже изврат если просто нужно удалить строки по какому - то простому условия. Этот алгоритм имеет смысл только если удаление строки зависит от данных в других строках. Тогда да.
---
А чем не понравился мой вариант (4) с хранением строк которые потом нужно удалить в отдельном массиве? Тем более что если речь идет о таблицах которые динамически отражаются на экране то добавление лишней колонки отнимет лишнее время :)
---
А чем не понравился мой вариант (4) с хранением строк которые потом нужно удалить в отдельном массиве? Тем более что если речь идет о таблицах которые динамически отражаются на экране то добавление лишней колонки отнимет лишнее время :)
:-)) Я понимаю, что причина в номерах строки, что сбивается. И в решении было видно, что работа идет с этим. А в вашем решении как будто 2 раза одно и тоже по циклу проходит. Код не только должен работать, но и быть понятным, мне просто другой вариант был чисто визуально понятнее. Может он по другим параметрам уступает, но тут это не так важно, этот объект пользователи используют самое частое раз в день. А по факту за прошлый год раз 10. Строк там мало, 5-6. Поэтому не так важно, сколько он будет отрабатывать.
---
Ну, это уже кому как нравиться. Приносить в жертву понятность и легкость восприятия программного кода в угоду лишней миллисекунде выполнения кода - я думаю, что не стоит. Если бы тут был объем данных, скажем, строк миллиард, то да. Я бы тогда написал уже код или с индексами, или методы статистического анализа применил. Или метод золотого сечения и пр. А тут задача локальная. Мне кажется, что не стоит.
---
Строка = ТаблицаДанных.ПолучитьСтроку (Сч); - только не получитьстроку, а получить.
Да, работает спасибо!
---
Ну да, конечно получить.
---
У вас похоже самый медленный алгоритм удаление из всех представленных. В каждой итерации вычисляется количество строк всей таблицы ТаблицаДанных.Количество () и доп.условия. Чтобы этого не было нужно перебирать с конца, как говорили остальные комментаторы.
Самый быстрый и легкий путь:

```1c
    Индекс = ТаблицаЗначений.Количество() - 1;
    Пока Индекс >= 0 Цикл
    Если УсловиеДляУдаленияСтроки(ТаблицаЗначений[Индекс]) Тогда
    ТаблицаЗначений.Удалить(Индекс);
    КонецЕсли;
    Индекс = Индекс - 1;
    КонецЦикла;
```

Ну если прямо хочется перебирать с начала по каким-то неведомым причинам, то хотя бы нужно переписать ваш код:

```1c
    Количество = ТаблицаДанных.Количество();
    Сч = 0;
    Пока (Сч < Количество) Цикл

    Если (УдаляемСтроку(ТаблицаДанных[Сч])) Тогда
    ТаблицаДанных.Удалить(Сч);
    Количество = ТаблицаДанных.Количество();
    Продолжить;
    КонецЕсли;

    Сч = Сч + 1;

    КонецЦикла;
```
---
Вообще - то количество строк вычисляется компилятором не при каждом обращении к функции КоличестроСтрок(), а просто возвращается из предвычисленного параметра. Т.к. КоличествоСтрок() - это просто функция которая возвращает свойство таблицы КоличествоСтрок. При удалении строки из этого свойства вычитается 1-ца, а при добавлении строки добавляется единица. Так что Вы тут не правы. Это аналог TList -
TList *List = new TList;
for (int i = 0; i < 10; i++)
{
List-Add((void *)(new float[10]));
}
и здесь при обращении int Num = List->Count - также не вычисляется кол-во элементов в списке List, - он просто храниться в свойстве потомка класса.
---
для небольших данных разница будет не существенна. На больших уже заметна.
Вот тест:

```1c
    &НаКлиенте
    Процедура Тест1(Команда)
    ВремяНачала = ТекущаяУниверсальнаяДатаВМиллисекундах();
    Сч = 0;
    Пока (Сч < ТЗРезультат.Количество()) Цикл
    Сч = Сч + 1;
    КонецЦикла;
    ВремяОкончания = ТекущаяУниверсальнаяДатаВМиллисекундах();
    Сообщить("Время выполнения: "+(ВремяОкончания - ВремяНачала));
    КонецПроцедуры

    &НаКлиенте
    Процедура Тест2(Команда)
    ВремяНачала = ТекущаяУниверсальнаяДатаВМиллисекундах();
    Сч = 0;
    Пока (Сч < КоличествоСтрокТЗ) Цикл
    Сч = Сч + 1;
    КонецЦикла;
    ВремяОкончания = ТекущаяУниверсальнаяДатаВМиллисекундах();
    Сообщить("Время выполнения: "+(ВремяОкончания - ВремяНачала));
    КонецПроцедуры
```

Для КоличествоСтрокТЗ = 1 000 000
Тест1: "Время выполнения: 7 128"
Тест2: "Время выполнения: 6 781"
---
Ну, во первых тут у Вас время в миллисекундах, и 200 миллисекунд разница. Для чистоты эксперимента надо прогнать алгоритм раз 100 и усреднить. Т.к. при запуске алгоритмов включается такие процессы, как использование кеша процессора/запуск других служб винды и пр. Тут судить нельзя по одному тесту. А во вторых:
Ну, это уже кому как нравиться. Приносить в жертву понятность и легкость восприятия программного кода в угоду лишней миллисекунде выполнения кода - я думаю, что не стоит. Если бы тут был объем данных, скажем, строк миллиард, то да. Я бы тогда написал уже код или с индексами, или методы статистического анализа применил. Или метод золотого сечения и пр. А тут задача локальная. Мне кажется, что не стоит.
---
А вот когда в ТЗ меняются строки, то становится совсем интересно:

```1c
    &НаКлиенте
    Процедура Тест1(Команда)
    ВремяНачала = ТекущаяУниверсальнаяДатаВМиллисекундах();
    Сч = 0;
    Пока (Сч < ТЗРезультат.Количество()) Цикл
    Если Сч%2 = 0 Тогда
    ТЗРезультат.Удалить(Сч);
    КонецЕсли;
    Сч = Сч + 1;
    КонецЦикла;
    ВремяОкончания = ТекущаяУниверсальнаяДатаВМиллисекундах();
    Сообщить("Тест1: Время выполнения: "+(ВремяОкончания - ВремяНачала));
    КонецПроцедуры

    &НаКлиенте
    Процедура Тест2(Команда)
    ВремяНачала = ТекущаяУниверсальнаяДатаВМиллисекундах();
    Сч = 0;
    Пока (Сч < КоличествоСтрокТЗ/2) Цикл
    Если Сч%2 = 0 Тогда
    ТЗРезультат.Удалить(Сч);
    КонецЕсли;
    Сч = Сч + 1;
    КонецЦикла;
    ВремяОкончания = ТекущаяУниверсальнаяДатаВМиллисекундах();
    Сообщить("Тест2: Время выполнения: "+(ВремяОкончания - ВремяНачала));
    КонецПроцедуры
```

Для КоличествоСтрокТЗ = 100 000
Тест1: Время выполнения: 26 286
Тест2: Время выполнения: 20 127

Более 6 секунд на 100 000 строках. Половина из которых удаляется.
Вот это уже затратно.
---
Хм. Я даже не знаю как это комментировать. Неужели не понятно, что при удалении строки будет пересчет количества строк. И вот в этом алгоритме -

```1c
    Пока (Сч < ТЗРезультат.Количество()) Цикл
    Если Сч%2 = 0 Тогда
    ТЗРезультат.Удалить(Сч);
    КонецЕсли;
    Сч = Сч + 1;
    КонецЦикла;
```

будет увеличение времени на пересчет.
А при удалении строк в алгоритме

```1c
    Пока (Сч < КоличествоСтрокТЗ/2) Цикл
    Если Сч%2 = 0 Тогда
    ТЗРезультат.Удалить(Сч);
    КонецЕсли;
    Сч = Сч + 1;
    КонецЦикла;
```

пересчет количества строк не будет - у Вас в переменной хранится (и процессор деление на два заменить на битовый сдвиг) - вы же не знаете сколько строк будет удалено. А тут у Вас известно - ровно половина. Этот алгоритм попахивает нечистотой эксперимента.
---
Я даже не знаю как это комментировать. Неужели не понятно, что при удалении строки будет пересчет количества строк.
ок. смотрим (18):
Вообще - то количество строк вычисляется компилятором не при каждом обращении к функции КоличестроСтрок(), а просто возвращается из предвычисленного параметра. Т.к. КоличествоСтрок() - это просто функция которая возвращает свойство таблицы КоличествоСтрок. При удалении строки из этого свойства вычитается 1-ца, а при добавлении строки добавляется единица
Комментировать и правда нечего. Все и так понятно.
---
Если Вы удаляете из таблицы строку, то из переменной ответственной за хранение кол-ва строк в таблице вычитается 1-ца. Это не относится к тому, что каждый раз при обращении к функции Количество() таблицы значений программа будет каждый раз пробегаться по строкам таблицы и подсчитывать их количество - так никто не делает при разработке компилятора транслятора - делают через хранение кол-ва строк в отдельной переменной - свойстве класса. Это же элементарно :-)
---
действительно не понимаете о чем речь, или специально в другую сторону уводите?
Удаление строк одинаково в обоих случаях. Тест1 и Тест2.
Если не удалять строки, то разница во времени выполнения не принципиальная. Логично, вычисление ТЗ.Количество() просто кешируется.
Если происходит удаление, то Количество() каждый раз выполняется. И разница во времени становится уже очень заметна.
Так что не надо говорить, что с условием ТЗ.Количество() не будет разницы. Вот о чем речь.
---
А у Вас метод такой - Вы задаете программе сколько надо удалить строк, и начинаете это количество строк удалять. Вопрос - откуда Вы знаете сколько строк надо удалить?
как у Вас:
Пока (Сч < КоличествоСтрокТЗ/2) Цикл
Если Сч%2 = 0 Тогда
ТЗРезультат.Удалить(Сч);
КонецЕсли;
Сч = Сч + 1;
КонецЦикла;

тут Вы откуда то еще до анализа таблицы уже знаете, что надо удалить половину строк таблицы.
---
смотрите алгоритм. В обоих Тест1 и Тест2 удаляются четные элементы. Это ровно половина выборки.
---
Ну а причем тут четные элементы выборки? - прочитайте постановку задачи у автора - ему надо удалить не четные элемент выборки, а анализировать строку на необходимость удаления. Зачем Вы делаете искусственные предположения, когда задача ясна из постановки?
---
мы не обсуждаем сейчас алгоритм автора топика. Мы обсуждаем утверждение, что:
Вообще - то количество строк вычисляется компилятором не при каждом обращении к функции КоличестроСтрок(), а просто возвращается из предвычисленного параметра. Т.к. КоличествоСтрок() - это просто функция которая возвращает свойство таблицы КоличествоСтрок. При удалении строки из этого свойства вычитается 1-ца, а при добавлении строки добавляется единица.
и второе противоречащее утверждение:
Я даже не знаю как это комментировать. Неужели не понятно, что при удалении строки будет пересчет количества строк.
Я привел абстрактный Тест проверки этих утверждений. Оба теста выполняют одинаковую работу. У обоих одинаковая итерация.
---
Ну, тогда таких искусственных алгоритмов можно много придумать которые будут быстрее работы некоторого алгоритма но уже в реальных данных. Ценность таких алгоритмов в чем? - просто доказать? - ну хорошо, Вы мне доказали. И?
---
ок. Вот еще тест:

```1c
    &НаКлиенте
    Процедура Тест3(Команда)
    ВремяНачала = ТекущаяУниверсальнаяДатаВМиллисекундах();
    Сч = 0;
    Пока (Сч < ТЗРезультат.Количество()) Цикл
    Если Сч < 1000 Тогда
    ТЗРезультат.Удалить(Сч);
    Иначе
    Прервать;
    КонецЕсли;
    Сч = Сч + 1;
    КонецЦикла;
    ВремяОкончания = ТекущаяУниверсальнаяДатаВМиллисекундах();
    Сообщить("Тест3: Время выполнения: "+(ВремяОкончания - ВремяНачала));

    КонецПроцедуры
```

Объясню алгоритм. Не важно сколько элементов в ТЗ. Всегда будут выполняться только проход и удаление первых 1000 элементов.
И вот итог:
Кол-во элементов в ТЗ | Время мсек
   10 000 | 99
 100 000 | 997
1 000 000 | 15 532

Показательно. Каждый раз именно рассчитывается количество элементов.
---
Нет, неправильно. При удалении строки производится перераспределение памяти. Если таблица большая, то и времени на перераспределение памяти больше. Это не относится к расчету кол-ва строк.
Аналог TList в c++ builder. Кстати, в предыдущих Ваших алгоритмах - тоже такая ситуация может быть. Т.к. все зависит от заполненности "кучи" памяти. И для чистоты эксперимента надо прогнать алгоритм раз 50 и потом усреднить.
---
как это соотносится с:
Т.к. КоличествоСтрок() - это просто функция которая возвращает свойство таблицы КоличествоСтрок. При удалении строки из этого свойства вычитается 1-ца, а при добавлении строки добавляется единица.
Предыдущие тесты (Тест1 и Тест2) оба удаляют строку. Временные затраты на это одинаковые.

Не надо притягивать алгоритмы с++ builder на работу 1С кода.
---
Относится просто - когда Вы удаляете строку из таблицы с кол-вом строк в 1000 - это одно, а когда из таблицы с кол-вом строк в 1000000 - это другое. Накладные расходы на перераспределение памяти в таблицах с разным кол-вом строк - разное. А по поводу c+++ builder - это я Вам пример привел просто для понимания - т.к. ТаблицаЗначений в 1С - это STL - контейнер. А TList в c++ builder - это динамический список очень похожий на STL - контейнер.
---
очередная попытка притянуть функциональность c++ builder к 1С.
В каком месте мы вызываем delete объекту? Согласно с++ объекты созданные в куче без явного удаления не уничтожаются.
Где мы выделяем память новому объекту?

Не стоит лезть во внутреннее строение платформы, не зная его механизмов.
---
delete вызывается неявно. Иначе бы при удалении строк/таблицы была бы утечка памяти. Это, я думал, все знают и не стал это писать.
То что Вы пишите - "Согласно с++ объекты созданные в куче без явного удаления не ничтожаются." - т.е. Вы хотите сказать, что когда я:
Табл = Новый ТаблицаЗначений
и потом
Табл = НеОпределено
память выделенная под Табл не возвращается операционке?
тогда сделайте миллиард Табл = Новый ТаблицаЗначений и также миллиард Табл = НеОпределено и посмотрите сколько памяти у Вас осталось. Уверяю - столько же.
"Где мы выделяем память новому объекту? " - когда делаете Новый (аналог new c++) - это и есть выделение памяти под новый объект.
---
ок. Скажу прямо: "сборка мусора" ничего не говорит?
---
Сборка мусора - это когда программа закрывается и планировщик вычищает не возвращенную память.
---
вот блин. Все программы на java и c# мертворожденные. Не успели загрузиться и уже выгружаются.
Дальше нечего обсуждать...
---
Ну, примерно в той же степени, как и ядерную атаку можно назвать сборкой мусора - мусор сгорит тоже :)
(53) Я терпел. Оскорблений больше не будет. Не вижу смысла продлжать разговор.
---
Вы хотите сказать, что когда я:
Табл = Новый ТаблицаЗначений
и потом
Табл = НеОпределено
память выделенная под Табл не возвращается операционке?
Если вот это дословно перевести на c++, то да. Будет явная утечка памяти.
Потому и говорю, не надо прямую ассоциацию приводить с с++
---
Какое еще перераспределение памяти в связанных списках?
---
Перераспределение памяти при удалении строки, а не перераспределении в списке. Т.к. память высвобождается и отдается операционке для использования другими процессорами - иначе была бы утечка памяти (хотя, этого добра хватает в 1С :-) ). Или Вы думаете что это бесплатная операция? - и на нее не тратится тактов процессора?
---
Оставим спорный момент возврата памяти операционке (по каждому чиху этого не делают и уж в одинэсной ТЗ - точно). Каким образом накладные расходы на удаление одной строки зависят от размера таблицы?
---
Зависят очень просто - чем больше сама таблица - тем больше она занимает страниц памяти. При удалении строк которые находятся в разных дампах(страницах) памяти процу приходится активно переключаться между дампами (страницами). Если таблица маленькая, и она убирается в одну страницу, то работа происходит в контексте одной страницы. Это если организована постраничная адресация. Если используется плоская модель памяти - то тут, возможно (надо посмотреть) и не будет увеличения времени удаления. + ко всему прочему надо учитывать объем кеша проца и какой объем данных закеширован.
---
Еще раз - в (43) было заявлено, что удаление ОДНОЙ строки в таблице бОльшего размера займет больше времени.
И теперь пытаетесь подвести под это утверждение что? Что одна строка в большой таблице будет занимать несколько страниц памяти? И при каждом удалении строки будет осуществляться возврат памяти операционке? Признайтесь, что ошиблись и перестаньте нести бред.
Насчет возврата памяти операционке - ознакомьтесь со значением слова "куча", которое вы тут употребляли и как она работает.
---
Ну не надо кидаться словами "бред". Строка может занимать память между двумя страницами - в конце одной и в начале другой. Давайте без оскорблений.
---
даже с++ не работает с ячейками памяти напрямую (если только специально взламывать). Она работает с виртуальным адресным пространством, которое ему выделяет ОС.
В итоге много терминов без понимания их сути.
---
для старый платформ вместо Строка = ТаблицаДанных.ПолучитьСтроку (Сч); пишем Строка = ТаблицаДанных.Получить (Сч);

в моей версии платформы нет такого метода для таблицы значений

и спс за это решение!
---
Строка = ТаблицаДанных.ПолучитьСтроку (Сч);
Без опечатки: Строка = ТаблицаДанных.Получить (Сч);
---
Кусок кода выложите как у вас удаление реализовано из тз
---
```1c
    Для каждого Строка из ТЗ Цикл
    НайденнаяСтрока = Список.Найти(Строка.Колонка, "Колонка");
    Если НайденнаяСтрока = Неопределено Тогда
    ТЗ.Удалить(Строка);
    КонецЕсли;
    КонецЦикла;
```
---
```1c
    УдаляемыеСтроки=новый массив;
    Для каждого Строка из ТЗ Цикл
    НайденнаяСтрока = Список.Найти(Строка.Колонка, "Колонка");
    Если НайденнаяСтрока = Неопределено Тогда
    УдаляемыеСтроки.Добавить(Строка);
    КонецЕсли;
    КонецЦикла;
    Для Каждого УдаляемаяСтрока из УдаляемыеСтроки Цикл
    ТЗ.Удалить(УдаляемаяСтрока);
    КонецЦикла;
```
---
Самый простой вариант:

```1c
    УдаляемыеСтроки=новый массив;
    Для Каждого СтрокаТЗ из ТЗ Цикл
    Если СтрокаТЗ.Сумма<0 Тогда
    УдаляемыеСтроки.Добавить(СтрокаТЗ);
    КонецЕсли;
    КонецЦикла;
    Для Каждого УдаляемаяСтрока из УдаляемыеСтроки Цикл
    ТЗ.Удалить(УдаляемаяСтрока);
    КонецЦикла;
```
---
Тоже всегда делаю именно так. Это самый наглядный и легко читаемый вариант из всех.
---
Спасибо всем. Нашла решение, которое показалось самым простым.
---
Вот самый быстрый и просто способ из всех:

```1c
    Индекс = ТаблицаЗначений.Количество() - 1;
    Пока Индекс >= 0 Цикл
    Если УсловиеДляУдаленияСтроки(ТаблицаЗначений[Индекс]) Тогда
    ТаблицаЗначений.Удалить(Индекс);
    КонецЕсли;
    Индекс = Индекс - 1;
    КонецЦикла;
```
---
одно из решений ответа из (3)!
---
А почему с конца не будет такого?
---
ответ на ваш вопрос дан в (3).
---
Этот способ только на первый взгляд самый быстрый. Во-первых, его можно записать короче:
```1c
    Для Индекс = - РабочаяТаблица.Количество() + 1 По 0 Цикл
    Если РабочаяТаблица[- Индекс][0] = 0 Тогда // условие удаления
    РабочаяТаблица.Удалить(- Индекс)
    КонецЕсли
    КонецЦикла
```
Во-вторых, даже в таком виде он выполняется примерно столько-же, сколько (7). Метод в (7) экономит на времени итерации переменной цикла, которая оказывается не нужна, когда элемент удален.
Но оба они (7) и (16) сильно проигрывают (примерно в два раза) методу с предварительным отбором списка удаляемых строк через НайтиСтроки() как в (5).
---
Но оба они (7) и (16) сильно проигрывают (примерно в два раза) методу с предварительным отбором списка удаляемых строк через НайтиСтроки() как в (5).
А за счет чего такой сильный проигрыш? Доступ по индексу такой медленный?
---
Полагаю, потому, что в "НайтиСтроки()" итерация ведется средствами С++, без накладных расходов интерпретатора языка 1С.

"НайтиСтроки()", однако, умеет проверять только точное совпадение с константой, и не подходит, если условие другое.
---
Если кого-то из академического интереса интересует "самый быстрый" способ, то даже конкурсы проходили - можно найти готовые обработки со сравнительным тестированием различных способов.
---
+(39)
на хиппо для 7.7 был первый конкурс на самое быстрое удаление строк из ТЗ с призами году в 2002. потом на мисте был конкурс для 8.1. не увидел метода копирования ТЗ с отбором обратным условием.
---
Этот метод (копирования) самый быстрый, примерно в 10 раз быстрее на миллионе строк:
```1c
    РабочаяТаблица = РабочаяТаблица.Скопировать(Новый Структура("Колонка1", 1))
```
Здесь удаляются строки с нулями, оставляются с единицей в Колонке1.
---
```1c
    Пока ТаблицаДанных.НайтиСтроки(Новый структура("Сумма", 0)).Количество() > 0 Цикл
    ТаблицаДанных.Удалить(ГруппыНоменклатуры.НайтиСтроки(Новый структура("Сумма", 0))[0]);
    КонецЦикла;
```

Хоть и поздно, но сейчас тоже гуглил эту проблему, попробовал лучший ответ, не вышло, но нашел свой вариант
---
Когда строк для удаления мало оптимально такой код.
Мы не гоняем данные в памяти, а просто перебираем.
Как говорится под каждую задачу, свое решение!

```1c
    Для Каждого Строка Из ОбъектыОшибок Цикл

    Если Строка.Ключ = "2" И ТипЗнч(Строка.Объект) = Тип("ДокументСсылка.УстановкаЦенНоменклатуры") Тогда

    ТекущийОбъект = Строка.Объект.ПолучитьОбъект();

    Если ТекущийОбъект <> Неопределено Тогда

    НужноЗаписать = Ложь;

    Товары = ТекущийОбъект.Товары;

    КоличествоСтрок = Товары.Количество();

    ТекущийИндекс = КоличествоСтрок - 1;

    Пока ТекущийИндекс >= 0 Цикл

    СтрокаТовары = Товары.Получить(ТекущийИндекс);

    Если СтрокаТовары.Номенклатура.ЭтоГруппа Тогда

    Товары.Удалить(СтрокаТовары);

    НужноЗаписать = Истина;

    КонецЕсли;

    ТекущийИндекс = ТекущийИндекс - 1;

    КонецЦикла;

    Если НужноЗаписать Тогда

    ТекущийОбъект.Записать();

    КонецЕсли;

    КонецЕсли;

    КонецЕсли;

    КонецЦикла;
```

В УПП умудрились папку впихнуть в документ.
---
Сообщение было скрыто модератором.