К статье
Практический материал

Разработка и Конфигурация · 12 мин

Как поменять местами элементы массива в 1С

Как поменять местами элементы массива в 1С: обмен через переменную, вставка и удаление, сортировка. Примеры кода на встроенном языке, ошибки и проверка результата.

Во встроенном языке 1С нет отдельной команды «поменять элементы местами», но задача решается несколькими строками кода. Массив в 1С — это объект типа «Массив», элементы которого доступны по индексу, начинающемуся с нуля. Чтобы обменять значения двух позиций, достаточно сохранить один элемент во временную переменную и выполнить два присваивания.

Такая операция нужна при ручной сортировке, изменении порядка строк для вывода в отчёт, реализации алгоритмов вроде пузырьковой сортировки или перемешивания данных. Ниже разобраны рабочие приёмы: классический обмен через переменную, перестановка методами Вставить/Удалить, сдвиг элементов и типичные ошибки, которые приводят к потере данных или ошибке «Индекс находится за границами массива».

Как устроен массив в 1С и почему это важно

Массив создаётся конструктором Новый Массив() или литералом, а элементы добавляются методом Добавить(). Доступ к элементу выполняется по индексу в квадратных скобках: Массив[0] — первый элемент, Массив[1] — второй. Нумерация всегда начинается с нуля, что часто становится источником ошибок у тех, кто привык к нумерации с единицы, как у строк таблицы значений при выводе пользователю.

Количество элементов возвращает метод Количество(). Последний допустимый индекс равен Массив.Количество() - 1. Попытка обратиться к несуществующему индексу вызывает исключение и останавливает выполнение кода, поэтому любой обмен элементов стоит начинать с проверки границ.

Элементы массива хранятся по ссылке на значение. Если элементом является объект (например, структура или другой массив), при обмене копируются ссылки, а не сами объекты. Для простых типов — чисел, строк, дат — обмен работает как обычное присваивание значений.

Обмен двух элементов через временную переменную

Универсальный и самый читаемый способ — классический обмен через третью переменную. Он работает для любых типов элементов и любых позиций в массиве.

Процедура ПоменятьЭлементыМестами(Массив, Индекс1, Индекс2)

Врем = Массив[Индекс1];

Массив[Индекс1] = Массив[Индекс2];

Массив[Индекс2] = Врем;

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

Пример использования: есть массив с названиями месяцев, нужно поменять местами первый и третий элементы.

Месяцы = Новый Массив;

Месяцы.Добавить("Январь");

Месяцы.Добавить("Февраль");

Месяцы.Добавить("Март");

ПоменятьЭлементыМестами(Месяцы, 0, 2);

// Теперь: Март, Февраль, Январь

Обратите внимание: массив передаётся в процедуру по ссылке, поэтому изменения внутри процедуры видны в вызывающем коде. Отдельно возвращать массив не требуется, хотя оформление в виде функции, возвращающей тот же массив, тоже допустимо и иногда удобнее для цепочек вызовов.

Проверка индексов перед обменом

Если индексы приходят из внешних данных — из параметров формы, файла обмена или пользовательского ввода — обязательна проверка, что оба индекса находятся в допустимом диапазоне и не равны друг другу. Обмен элемента с самим собой безвреден, но бессмыслен, а выход за границы массива прервёт выполнение кода ошибкой.

Функция БезопасныйОбмен(Массив, Индекс1, Индекс2)

Всего = Массив.Количество();

Если Индекс1 < 0 Или Индекс2 < 0

Или Индекс1 >= Всего Или Индекс2 >= Всего Тогда

Возврат Ложь;

КонецЕсли;

Если Индекс1 = Индекс2 Тогда

Возврат Истина; // менять нечего

КонецЕсли;

Врем = Массив[Индекс1];

Массив[Индекс1] = Массив[Индекс2];

Массив[Индекс2] = Врем;

Возврат Истина;

КонецФункции

Возврат булева значения позволяет вызывающему коду понять, выполнен обмен или нет, и отреагировать: записать предупреждение в журнал регистрации или показать сообщение пользователю.

Перестановка методами Вставить и Удалить

Альтернативный приём — извлечь элемент методом Удалить() и поместить его в новую позицию методом Вставить(). Такой подход удобен, когда нужно не просто обменять два элемента, а переместить один элемент на место другого со сдвигом остальных.

// Переместить элемент с позиции 0 на позицию 2

Значение = Массив[0];

Массив.Удалить(0);

Массив.Вставить(2, Значение);

Здесь есть тонкость: после удаления элемента индексы всех последующих позиций смещаются на единицу влево. Если целевая позиция находилась правее удалённого элемента, её нужно скорректировать. В примере выше после удаления нулевого элемента массив стал короче на один, и вставка по индексу 2 ставит значение именно на третью позицию уже нового массива.

Для простого обмена двух элементов этот способ избыточен и легче допускает ошибку в смещении индексов. Используйте его, когда задача формулируется именно как «переместить элемент вверх/вниз по списку», например кнопками «Вверх» и «Вниз» в табличной части, собранной на массиве.

Типичные ошибки
01
Обмен без временной переменной: Массив[0] = Массив[1]; Массив[1] = Массив[0] — оба элемента получат одно значение, второе потеряется.
02
Нумерация с единицы вместо нуля — обращение к Массив[Количество()] вызывает ошибку выхода за границы.
03
Игнорирование смещения индексов после Удалить() — элемент вставляется не на ту позицию.
04
Обмен в цикле сортировки без пересчёта границ при пустом массиве — обращение к несуществующему элементу.

Обмен соседних элементов и сдвиг в цикле

Частная задача — поменять элемент с соседним, то есть поднять или опустить его на одну позицию. Это тот же обмен через временную переменную, но второй индекс вычисляется как Индекс + 1 или Индекс - 1. Проверка границ здесь особенно важна: у первого элемента нет соседа сверху, у последнего — снизу.

// Поднять элемент на одну позицию вверх

Если Индекс > 0 Тогда

Врем = Массив[Индекс - 1];

Массив[Индекс - 1] = Массив[Индекс];

Массив[Индекс] = Врем;

КонецЕсли;

На основе такого обмена строится пузырьковая сортировка: вложенные циклы сравнивают соседние элементы и меняют их местами, пока массив не упорядочится. Для маленьких массивов это приемлемо, но на больших объёмах алгоритм работает медленно, и лучше рассмотреть встроенные средства, о которых ниже.

Альтернативы: сортировка и другие структуры данных

Если обмен элементов нужен только для упорядочивания, вручную переставлять значения не обязательно. У массива нет собственного метода сортировки, но задачу решают смежные объекты платформы.

Сравнение вариантов

Обмен через переменную

Подходит для точечной перестановки двух известных позиций. Минимум кода, полный контроль, но сортировку придётся реализовывать самостоятельно.

СписокЗначений

Имеет метод СортироватьПоЗначению() и Сдвинуть(). Удобен для списков строк с представлениями, но хранит пары значение-представление.

ТаблицаЗначений

Метод Сортировать() по одной или нескольким колонкам, метод Сдвинуть() для строк. Оптимальна для структурированных данных, но тяжелее массива.

Вставить/Удалить

Подходит для перемещения элемента на произвольную позицию со сдвигом остальных. Требует аккуратного пересчёта индексов.

У СписокЗначений есть метод Сдвинуть(Элемент, КоличествоПозиций), который перемещает элемент вверх или вниз без ручной работы с индексами. У ТаблицаЗначений аналогичный метод работает со строками. Если данные изначально хранятся в этих структурах, переносить их в массив ради перестановки не нужно.

Для произвольного порядка сортировки массива по сложному правилу применяют приём с промежуточной таблицей значений: выгружают элементы в колонку, добавляют колонку ключа сортировки, сортируют таблицу и выгружают обратно. Это надёжнее, чем самописный алгоритм на больших объёмах.

Маршрут решения

Как выбрать действие

Нужно поменять два конкретных элемента по известным индексамИспользуйте обмен через временную переменную с проверкой границ
Нужно поднять или опустить элемент на одну позициюОбмен с соседним индексом или метод Сдвинуть() у списка значений
Нужно упорядочить весь массивВыгрузите в таблицу значений и примените Сортировать(), либо используйте список значений
Индексы приходят извне и могут быть некорректныСначала проверьте диапазон 0..Количество()-1 и равенство индексов

Проверка результата

После обмена убедитесь, что массив содержит ожидаемый порядок. Самый простой способ в отладке — вывести элементы в цикле через Сообщить() или посмотреть содержимое массива в табло отладчика, установив точку останова сразу после обмена.

Для Инд = 0 По Массив.ВГраница() Цикл

Сообщить(Строка(Инд) + ": " + Массив[Инд]);

КонецЦикла;

Метод ВГраница() возвращает индекс последнего элемента и удобнее, чем Количество() - 1, тем что не даёт ошибки на пустом массиве: цикл просто не выполнится. Для автоматической проверки в тестах сравнивайте значения по конкретным индексам до и после обмена.

Контрольные точки

Как проверить результат

Порядок элементов
Норма

Значения на целевых индексах поменялись местами, остальные на своих позициях

Тревожный признак

Оба элемента содержат одинаковое значение — обмен выполнен без временной переменной

Количество элементов
Норма

Количество() до и после обмена совпадает

Тревожный признак

Массив стал короче или длиннее — случайно использованы Удалить/Добавить

Выполнение кода
Норма

Процедура завершается без исключений

Тревожный признак

Ошибка «Индекс находится за границами массива» — индексы не проверены

Ограничения и нюансы

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

Фиксированный массив (ФиксированныйМассив) изменить нельзя — попытка присвоить элемент по индексу вызовет ошибку. Если получили фиксированный массив, например из параметров или свойств объекта, сначала скопируйте его в обычный массив, перебрав элементы в цикле.

Для многомерных массивов (массив массивов) обмен выполняется на том уровне, где лежат переставляемые элементы: сначала получите вложенный массив по индексу внешнего, затем меняйте элементы внутри него тем же приёмом через временную переменную.

Итог

Что важно запомнить

Обмен элементов массива в 1С делается через временную переменную и два присваивания. Индексация идёт с нуля, границы проверяются через Количество() или ВГраница(). Для сортировки и сдвига удобнее список значений или таблица значений, а фиксированный массив перед изменениями нужно скопировать в обычный.

Частые вопросы

Можно ли поменять элементы местами одной строкой без временной переменной?

Надёжного способа нет. В некоторых языках используют арифметический трюк или кортежное присваивание, но во встроенном языке 1С кортежей нет, а арифметический обмен работает только для чисел и чреват переполнением и потерей точности. Временная переменная — правильное и читаемое решение.

Как поменять местами строки табличной части документа?

Табличная часть поддерживает индексацию строк, поэтому применим тот же приём: сохраните данные одной строки во временную структуру или скопируйте значения полей поочерёдно. Для сдвига строки на одну позицию удобнее выгрузить табличную часть в таблицу значений, использовать метод Сдвинуть() и загрузить обратно.

Что произойдёт, если поменять элемент с самим собой?

Ничего страшного: элемент получит собственное значение, массив не изменится. Тем не менее в коде стоит явно пропускать случай равных индексов — это делает логику прозрачной и избавляет от лишних присваиваний в циклах сортировки.

Как перемешать массив в случайном порядке?

Используйте алгоритм тасования: пройдите по массиву от последнего элемента к первому и меняйте текущий элемент со случайным из диапазона от нуля до текущего индекса. Случайное число получите через объект ГенераторСлучайныхЧисел с методом СлучайноеЧисло(). Каждый обмен — та же перестановка через временную переменную.

Почему обмен работает в отладчике, но не сохраняется в базе?

Массив — структура в памяти, он не хранится в базе сам по себе. Если массив построен из данных объектов, после перестановки нужно записать изменённые объекты или сохранить новый порядок явно, например в реквизите с номером строки или в регистре сведений.

Есть ли у массива метод Сортировать?

Нет, у объекта Массив такого метода нет. Для сортировки выгрузите элементы в ТаблицуЗначений и вызовите Сортировать(), либо используйте СписокЗначений с методом СортироватьПоЗначению(). Ручная сортировка обменами оправдана только для маленьких массивов или особых правил упорядочивания.