В процессе разработки и проведения анализа структуры метаданных на платформе 1С:Предприятие 8 часто возникает задача сортировки данных, находящихся в коллекциях, таких как Массив или ФиксированныйМассив, содержащих Структуры или Соответствия. Стандартным и наиболее простым способом является использование объекта ТаблицаЗначений с его мощным методом Сортировать(). Однако этот объект доступен исключительно на стороне сервера. В данной статье мы проанализируем ситуацию, когда использование ТаблицыЗначений невозможно или нежелательно (например, при работе на тонком клиенте), и рассмотрим альтернативные способы решения этой задачи.
Рассмотрим ситуацию, когда нам необходимо отсортировать массив структур прямо на клиенте, не прибегая к вызову серверного контекста. Это может быть критично для производительности интерфейса. Один из наиболее оригинальных способов — использование комбинации объектов СписокЗначений и Соответствие.
Суть метода заключается в том, что СписокЗначений имеет метод СортироватьПоЗначению(), который доступен на клиенте. Мы можем использовать поле, по которому нужно выполнить сортировку, в качестве значения элемента списка, а саму структуру хранить в связанном объекте Соответствие. Выясним, как это реализовать программно:
Функция ОтсортироватьКоллекциюНаКлиенте(Коллекция, ИмяПоляСортировки, Направление = "Возр") Экспорт
НаправлениеСортировки = ?(Направление = "Возр", НаправлениеСортировки.Возр, НаправлениеСортировки.Убыв);
// Используем соответствие для группировки элементов с одинаковыми значениями ключа
ДанныеСортировки = Новый Соответствие;
СписокКлючей = Новый СписокЗначений;
// Специальный массив для обработки значений Неопределено (т.к. Неопределено не может быть ключом соответствия)
МассивНеопределено = Новый Массив;
Для Каждого Элемент Из Коллекция Цикл
ЗначениеКлюча = Элемент[ИмяПоляСортировки];
Если ЗначениеКлюча = Неопределено Тогда
МассивНеопределено.Добавить(Элемент);
Продолжить;
КонецЕсли;
СписокЭлементов = ДанныеСортировки[ЗначениеКлюча];
Если СписокЭлементов = Неопределено Тогда
СписокЭлементов = Новый Массив;
ДанныеСортировкиВставить(ЗначениеКлюча, СписокЭлементов);
СписокКлючей.Добавить(ЗначениеКлюча);
КонецЕсли;
СписокЭлементов.Добавить(Элемент);
КонецЦикла;
// Используем штатный метод СпискаЗначений
СписокКлючей.СортироватьПоЗначению(НаправлениеСортировки);
Результат = Новый Массив;
// Если нужно, чтобы Неопределено было в начале (при возрастании)
Если Направление = "Возр" Тогда
Для Каждого Эл Из МассивНеопределено Цикл
Результат.Добавить(Эл);
КонецЦикла;
КонецЕсли;
Для Каждого ЭлементСписка Из СписокКлючей Цикл
Ключ = ЭлементСписка.Значение;
СписокЭлементов = ДанныеСортировки[Ключ];
Для Каждого Эл Из СписокЭлементов Цикл
Результат.Добавить(Эл);
КонецЦикла;
КонецЦикла;
// Если нужно, чтобы Неопределено было в конце (при убывании)
Если Направление <> "Возр" Тогда
Для Каждого Эл Из МассивНеопределено Цикл
Результат.Добавить(Эл);
КонецЦикла;
КонецЕсли;
Возврат Результат;
КонецФункции
Разберем этот код подробнее. Мы создаем СписокЗначений, в который помещаем только те данные, по которым будет идти сравнение. Объект Соответствие позволяет нам быстро найти исходную структуру по значению ключа. Важный нюанс: если в коллекции несколько элементов имеют одинаковое значение поля сортировки, мы храним их в массиве внутри соответствия, чтобы не потерять данные.
Если специфика задачи позволяет выполнить серверный вызов, самым надежным методом остается использование ТаблицыЗначений. Рассмотрим, как сделать это максимально универсально. Проанализируем пример функции, которая принимает любую коллекцию и возвращает отсортированный массив:
Функция СортироватьКоллекциюЧерезТЗ(Коллекция, ИмяПоля, Порядок = "Возр") Экспорт
ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Объект");
ТЗ.Колонки.Добавить("ПолеСортировки");
Для Каждого Элемент Из Коллекция Цикл
НоваяСтрока = ТЗ.Добавить();
НоваяСтрока.Объект = Элемент;
// Работаем через обращение по имени поля для универсальности
НоваяСтрока.ПолеСортировки = Элемент[ИмяПоля];
КонецЦикла;
ТЗ.Сортировать("ПолеСортировки " + Порядок);
Возврат ТЗ.ВыгрузитьКолонку("Объект");
КонецФункции
Обратим внимание на важный момент оптимизации. Если ваша коллекция — это простой Массив простых значений (строк или чисел), вы можете ускорить процесс заполнения таблицы, используя метод ЗагрузитьКолонку(). Проанализируем, как это сокращает код:
// Пример быстрой загрузки массива в ТЗ
ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Значение");
// Создаем нужное количество строк заранее
Для н = 1 По ИсходныйМассив.Количество() Цикл
ТЗ.Добавить();
КонецЦикла;
// Загружаем данные одной операцией
ТЗ.ЗагрузитьКолонку(ИсходныйМассив, "Значение");
ТЗ.Сортировать("Значение Возр");
Результат = ТЗ.ВыгрузитьКолонку("Значение");
Необходимо отметить, что начиная с версии платформы 8.3.24, компания 1С реализовала долгожданную возможность: метод Сортировать() непосредственно у объекта Массив. Это делает большинство старых "обходных" путей неактуальными для современных конфигураций.
Посмотрим на пример использования этого метода для массива структур:
// Массив структур
МассивДанных = Новый Массив;
МассивДанных.Добавить(Новый Структура("Имя, Возраст", "Иван", 25));
МассивДанных.Добавить(Новый Структура("Имя, Возраст", "Анна", 22));
// Сортировка по полю "Возраст" по возрастанию
МассивДанных.Сортировать("Возраст Возр");
Преимущества данного метода:
В некоторых специфических задачах, когда нужно отсортировать большой объем текстовых данных на клиенте, можно применить объект ТекстовыйДокумент. Рассмотрим этот "лайфхак":
ТекстДок = Новый ТекстовыйДокумент;
Для Каждого СтрокаДанных Из МассивСтрок Цикл
ТекстДок.ДобавитьСтроку(СтрокаДанных);
КонецЦикла;
// Встроенный метод сортировки текстовых строк
ТекстДок.Сортировать();
ОтсортированныйМассив = Новый Массив;
Для н = 1 По ТекстДок.КоличествоСтрок() Цикл
ОтсортированныйМассив.Добавить(ТекстДок.ПолучитьСтроку(н));
КонецЦикла;
Этот способ эффективен только для одномерных массивов строк, но он работает значительно быстрее, чем самописный алгоритм "пузырька" на языке 1С.
Важно помнить о фундаментальном ограничении: на клиенте 1С не хранит все данные объекта. Если вы пытаетесь отсортировать массив ссылок (например, СправочникСсылка.Номенклатура) по наименованию, находясь на клиенте, система может выдать неверный результат. Это связано с тем, что сортировка будет идти по представлению, которое закэшировано на клиенте. Если представление еще не получено с сервера, сортировка может быть выполнена некорректно (например, по внутреннему идентификатору GUID).
Рекомендация: Если требуется гарантированная сортировка по реквизитам ссылочных объектов (Наименование, Артикул, Дата документа), всегда выполняйте эту операцию на сервере через запрос или ТаблицуЗначений.
Подводя итог нашему анализу, дадим несколько практических советов по выбору метода сортировки:
Массив.Сортировать(). Это самый быстрый и правильный путь.СпискомЗначений и Соответствием (Решение 1).ТаблицуЗначений. Помните, что передача больших коллекций между клиентом и сервером может быть накладной, поэтому иногда выгоднее отсортировать данные в момент их получения из базы данных.