Как отсортировать элементы массива в 1С:Предприятие?

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

При разработке прикладных решений на платформе 1С:Предприятие разработчики регулярно сталкиваются с необходимостью упорядочивания данных в коллекциях. Иногда в терминологии возникает путаница: начинающие специалисты могут называть операцию упорядочивания "группировкой" (как это произошло в исходном обсуждении на форуме). Однако для превращения хаотичного набора чисел вроде (2, 4, 3, 1) в последовательный ряд (1, 2, 3, 4) нам требуется именно сортировка.

Поскольку в классической платформе 1С:Предприятие 8 у объекта Массив отсутствует встроенный метод прямой сортировки, программистам приходится использовать различные обходные пути. Давайте детально разберем и проанализируем пять наиболее эффективных способов решения этой задачи в зависимости от объема данных, их типа и используемой версии платформы.

Способ 1. Использование объекта СписокЗначений (классическое решение)

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

Рассмотрим по шагам программный код, реализующий данный алгоритм:


// Исходный неотсортированный массив чисел
Мас = Новый Массив;
Мас.Добавить(2);
Мас.Добавить(4);
Мас.Добавить(3);
Мас.Добавить(1);

// Инициализируем вспомогательный СписокЗначений
СЗ = Новый СписокЗначений;

// Загружаем элементы массива в список значений
СЗ.ЗагрузитьЗначения(Мас);

// Выполняем сортировку по значению в направлении возрастания
СЗ.СортироватьПоЗначению(НаправлениеСортировки.Возр);

// Выгружаем упорядоченные элементы обратно в исходный массив
Мас = СЗ.ВыгрузитьЗначения();

Выясним причину, почему при работе с реальной базой данных этот способ требует осторожности. Если ваш массив содержит не простые числа или строки, а ссылки на элементы базы данных (например, ссылки на справочник Контрагенты или Номенклатура), метод СортироватьПоЗначению() отработает некорректно с точки зрения пользователя. Платформа отсортирует ссылки по их внутреннему уникальному идентификатору (GUID), что визуально будет выглядеть как хаотичный набор данных.

Для решения этой проблемы в объекте СписокЗначений предусмотрен альтернативный метод. Посмотрим на пример сортировки ссылочных типов:


// Если в массиве хранятся ссылки на справочники, сортируем их по представлению (наименованию)
СЗ = Новый СписокЗначений;
СЗ.ЗагрузитьЗначения(МассивСсылок);
СЗ.СортироватьПоПредставлению(НаправлениеСортировки.Возр);
МассивСсылок = СЗ.ВыгрузитьЗначения();

Способ 2. Использование Таблицы Значений (для сложных структур данных)

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

В этом случае на помощь приходит объект ТаблицаЗначений. Мы можем динамически создать таблицу, определить в ней необходимые колонки, перенести туда данные из массива, выполнить сортировку по любому набору колонок и вернуть результат обратно в массив. Разберем этот процесс на практическом примере:


// Исходный массив структур с информацией о товарах
МассивТоваров = Новый Массив;
МассивТоваров.Добавить(Новый Структура("Наименование, Количество", "Товар Б", 10));
МассивТоваров.Добавить(Новый Структура("Наименование, Количество", "Товар А", 5));
МассивТоваров.Добавить(Новый Структура("Наименование, Количество", "Товар В", 20));

// Создаем таблицу значений для сортировки
ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Наименование", Новый ОписаниеТипов("Строка"));
ТЗ.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число"));
ТЗ.Колонки.Добавить("ИсходнаяСтруктура"); // Колонка для хранения исходного объекта

// Заполняем таблицу значений данными из массива
Для Каждого ЭлементМассива Из МассивТоваров Цикл
    НоваяСтрока = ТЗ.Добавить();
    ЗаполнитьЗначенияСвойств(НоваяСтрока, ЭлементМассива);
    НоваяСтрока.ИсходнаяСтруктура = ЭлементМассива;
КонецЦикла;

// Сортируем таблицу значений по колонке "Наименование" по возрастанию
ТЗ.Сортировать("Наименование Возр");

// Переносим отсортированные структуры обратно в исходный массив
МассивТоваров.Очистить();
Для Каждого СтрокаТЗ Из ТЗ Цикл
    МассивТоваров.Добавить(СтрокаТЗ.ИсходнаяСтруктура);
КонецЦикла;

Способ 3. Сортировка через Запрос (для больших массивов и ссылок)

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

Передача массива в запрос в качестве параметра позволяет СУБД быстро обработать данные во временной таблице, проиндексировать их при необходимости и вернуть обратно уже в отсортированном виде. Рассмотрим подробнее код такой операции:


// Исходный массив ссылок на документы или справочники
МассивДляСортировки = ПолучитьИсходныйМассив(); 

Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ВременныйИсточник.Ссылка КАК Ссылка
    |ПОМЕСТИТЬ ВТ_ИсходныеДанные
    |ИЗ
    |	&МассивДляСортировки КАК ВременныйИсточник
    |;
    |
    |////////////////////////////////////////////////////////////////////////////////
    |ВЫБРАТЬ
    |	ВТ_ИсходныеДанные.Ссылка КАК Ссылка
    |ИЗ
    |	ВТ_ИсходныеДанные КАК ВТ_ИсходныеДанные
    |
    |УПОРЯДОЧИТЬ ПО
    |	ВТ_ИсходныеДанные.Ссылка.Наименование ВОЗР"; // Сортируем средствами базы данных по наименованию

Запрос.УстановитьПараметр("МассивДляСортировки", МассивДляСортировки);

РезультатЗапроса = Запрос.Выполнить();
Если Не РезультатЗапроса.Пустой() Тогда
    // Выгружаем отсортированную колонку обратно в массив
    МассивДляСортировки = РезультатЗапроса.Выгрузить().ВыгрузитьКолонку("Ссылка");
КонецЕсли;

Способ 4. Использование COM-объекта ArrayList (только для Windows-серверов)

Существует еще один специализированный способ быстрой сортировки массивов в оперативной памяти без обращения к СУБД или метаданным 1С. Мы можем использовать внешнюю системную библиотеку .NET Framework через COM-соединение. Данный способ работает быстрее стандартных коллекций 1С при обработке гигантских массивов в оперативной памяти, но помните о важном ограничении: этот код успешно выполнится только на серверах под управлением ОС Windows.

Проанализируем пример использования COM-объекта ArrayList:


Попытка
    // Создаем .NET объект ArrayList через COM
    СписокNET = Новый COMОбъект("System.Collections.ArrayList");
Исключение
    // Обработка исключения, если код выполняется на Linux-сервере
    ВызватьИсключение "Использование System.Collections.ArrayList недоступно на данной платформе.";
КонецПопытки;

// Заполняем ArrayList элементами из нашего массива 1С
СписокNET.Add(2);
СписокNET.Add(4);
СписокNET.Add(3);
СписокNET.Add(1);

// Вызываем нативный оптимизированный метод сортировки .NET
СписокNET.Sort();

// Переносим отсортированные элементы обратно в массив 1С
Мас = Новый Массив;
Для Индекс = 0 По СписокNET.Count - 1 Цикл
    Мас.Добавить(СписокNET.Item(Индекс));
КонецЦикла;

Способ 5. Современный стек 1С:Элемент и 1С:Исполнитель

В новейших технологиях экосистемы "1С" (платформа нового поколения "1С:Элемент" и язык сценариев "1С:Исполнитель") встроенный язык претерпел серьезные архитектурные изменения. Разработчики наконец получили долгожданный нативный метод сортировки массивов "из коробки" без необходимости использования обходных путей. Более того, метод поддерживает лаконичные лямбда-выражения (стрелочные функции).

Посмотрим на пример сортировки массива чисел в современном синтаксисе:


// Сортировка простого списка значений по возрастанию
Перем Список = [2, 4, 3, 1];
Список = Список.СортироватьПо(Элемент -> Элемент);

А так выглядит изящная сортировка массива структур по конкретному свойству в новых средах разработки 1С:


// Сортировка массива объектов по убыванию оценки
Перем Студенты = ПолучитьСписокСтудентов();
Студенты = Студенты.СортироватьПо(Студент -> Студент.Оценка, НаправлениеСортировки.ПоУбыванию);

Историческая справка: Дональд Кнут и алгоритмы

В завершение обсуждения затронем интересный момент, упомянутый участниками форума. При обсуждении базовых алгоритмов сортировки (таких как сортировка пузырьком, вставками или быстрая сортировка Хоара) разработчики часто ссылаются на фундаментальный труд Дональда Кнута "Искусство программирования".

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

  1. Том 2 ("Получисленные алгоритмы") посвящен генерации случайных чисел и арифметике (работе с плавающей запятой, системам счисления и т. д.).
  2. Том 3 ("Сортировка и поиск") — именно эта книга целиком и полностью посвящена классическим алгоритмам упорядочивания данных и быстрого нахождения нужной информации в структурах данных.

Таким образом, для глубокого изучения математической теории и принципов работы алгоритмов сортировки, которые лежат под капотом СУБД и платформы 1С, вам следует обращаться именно к третьему тому великого труда Дональда Кнута.

← На главную