Как правильно удалить четные числа или элементы из массива в 1С

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Работа с массивами — это базовая задача для любого разработчика 1С, однако операция удаления элементов «на лету» внутри цикла часто вызывает затруднения. Основная сложность заключается в том, что при удалении элемента индексы всех последующих элементов сдвигаются, и стандартный обход коллекции начинает работать некорректно. В этой статье мы подробно разберем, как эффективно удалять элементы, будь то четные числа (по значению) или каждый второй элемент (по индексу), и выясним, какой подход считается наиболее профессиональным.

Постановка задачи и типичные ошибки

Прежде всего, проанализируем ситуацию, в которой оказался автор темы. Задача состояла в том, чтобы создать массив чисел и удалить из него все четные значения, при этом размер массива должен уменьшиться. Часто возникает путаница: что именно нужно удалить? Существует три разных интерпретации этой задачи:

  1. Удаление по значению: удаляем числа, которые делятся на 2 без остатка (например, 2, 4, 1000).
  2. Удаление по индексу: удаляем каждый второй элемент массива (первый, третий, пятый и т.д.).
  3. Удаление по четности индекса: удаляем элементы, находящиеся на позициях 0, 2, 4...

Рассмотрим подробнее каждую из этих ситуаций и подберем оптимальный программный код.

Решение 1: Удаление четных чисел (по значению) с использованием цикла «Пока»

Это классический способ решения задачи, если мы хотим избежать проблем со сдвигом индексов при обходе массива с начала. Главная хитрость здесь заключается в том, что мы увеличиваем счетчик индекса только в том случае, если не удаляли элемент. Если же элемент был удален, текущий индекс переходит на следующий (сдвинутый) элемент автоматически, и нам нужно проверить его еще раз на той же позиции.

Рассмотрим пример кода:


Индекс = 0;
Пока Индекс < Массив.Количество() Цикл
    // Проверяем значение элемента на четность
    Если Массив[Индекс] % 2 = 0 Тогда
        // Если число четное, удаляем его
        Массив.Удалить(Индекс);
        // Индекс НЕ увеличиваем, так как на место удаленного встал следующий элемент
    Иначе
        // Если число нечетное, просто переходим к следующему
        Индекс = Индекс + 1;
    КонецЕсли;
КонецЦикла;

В этом примере мы используем метод Массив.Количество() внутри условия цикла. Это позволяет нам динамически отслеживать уменьшение размера коллекции. Как только Индекс станет равным новому количеству элементов, цикл завершится без ошибок выхода за границы массива.

Решение 2: Удаление элементов с конца (Золотой стандарт)

Многие опытные разработчики называют этот метод наиболее надежным. Проанализируем, почему. Когда мы начинаем обход массива с последнего элемента и движемся к нулевому, удаление элемента никак не влияет на индексы тех элементов, которые нам еще предстоит обработать. Текущий «хвост» массива сдвигается влево в уже «просмотренную» область.

Посмотрим на пример реализации удаления четных чисел при обходе с конца:


ВсегоЭлементов = Массив.Количество();
Для Счетчик = 1 По ВсегоЭлементов Цикл
    // Вычисляем индекс с конца
    Индекс = ВсегоЭлементов - Счетчик;
    
    Если Массив[Индекс] % 2 = 0 Тогда
        Массив.Удалить(Индекс);
    КонецЕсли;
КонецЦикла;

Этот подход исключает необходимость манипуляций со счетчиком внутри цикла и считается «интуитивно понятным» для платформы 1С. Мы четко фиксируем количество итераций и не боимся ошибки "Индекс находится за границами массива".

Решение 3: Удаление каждого второго элемента (по позиции)

Иногда задача стоит иначе: нужно удалить каждый четный элемент по порядку (например, 2-й, 4-й, 6-й). Здесь можно применить математический подход. Если мы удаляем каждый раз элемент, который идет следом за текущим, можно использовать упрощенный цикл.

Разберем интересный пример, предложенный участниками обсуждения:


КоличествоУдаляемых = Цел(Массив.Количество() / 2);
Для Индекс = 1 По КоличествоУдаляемых Цикл
    // При каждом удалении массив схлопывается, 
    // поэтому мы можем всегда удалять элемент на определенной позиции
    Массив.Удалить(Индекс); 
КонецЦикла;

Важно: этот метод требует внимательного расчета начального индекса и количества итераций в зависимости от того, считается ли первый элемент (индекс 0) четным или нечетным в контексте вашей задачи.

Решение 4: Использование временного массива (для больших данных)

Выясним причину, почему удаление элементов в цикле может работать медленно. Метод Удалить() заставляет систему физически перезаписывать память, сдвигая все элементы, стоящие после удаленного. Если в массиве 100 000 элементов и вы удаляете 50 000 из них, это может занять значительное время (сложность алгоритма O(n²)).

В профессиональной разработке часто выгоднее создать новый массив и перенести в него только те элементы, которые соответствуют условию:


НовыйМассив = Новый Массив;
Для Каждого Элемент Из Массив Цикл
    Если Элемент % 2 <> 0 Тогда
        НовыйМассив.Добавить(Элемент);
    КонецЕсли;
КонецЦикла;
Массив = Новый Массив(НовыйМассив); // Заменяем старый массив новым

Этот метод работает за линейное время O(n), что критически важно для производительности системы при работе с большими объемами данных.

Важные замечания по типам данных

В процессе обсуждения на форуме было отмечено, что в массиве могут находиться не только числа. Если ваш массив содержит разнородные данные (строки, ссылки, структуры), попытка выполнить операцию % 2 приведет к аварийному завершению программы.

Рассмотрим правило хорошего тона: перед проверкой на четность всегда проверяйте тип значения. Это сделает ваш код отказоустойчивым.


Если ТипЗнч(Массив[Индекс]) = Тип("Число") Тогда
    Если Массив[Индекс] % 2 = 0 Тогда
        Массив.Удалить(Индекс);
    КонецЕсли;
КонецЕсли;

Подведем итоги

Мы проанализировали несколько способов решения задачи. Для простых учебных задач или небольших массивов идеально подходит удаление с конца или цикл «Пока» с ручным управлением индексом. Для высоконагруженных систем или работы с огромными коллекциями лучше использовать метод создания нового массива или даже временные таблицы в запросах (если данные числовые). Выбор метода зависит от ваших приоритетов: читаемость кода или скорость его выполнения.

← На главную