Как исправить неправильную сортировку чисел в табличной части или массиве 1С

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

Каждый начинающий разработчик в среде «1С:Предприятие» рано или поздно сталкивается со странным поведением сортировки чисел. Мы ожидаем увидеть логичный ряд по возрастанию: 1, 3, 4, 23, 100, 263. Однако платформа внезапно выдает нам последовательность вида: 1, 100, 23, 263, 3, 4. Такое поведение может поставить в тупик, особенно во время непрерывной и изнурительной работы, когда внимание притупляется.

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

Выясняем причину: Лексикографическое сравнение против математического

Для начала давайте проанализируем ситуацию и поймем, почему платформа 1С сортирует числа столь неочевидным образом. Причина кроется в типах данных.

Если колонка вашей табличной части, таблицы значений или элементы массива имеют тип Строка, то платформа применяет к ним правила текстового (лексикографического) сравнения. При такой сортировке символы анализируются поочередно слева направо:

  1. Сначала сравниваются первые символы строк. Символ "1" меньше символа "2", поэтому строки, начинающиеся с "1" (например, "100"), всегда будут идти перед строками, начинающимися с "2" (например, "23").
  2. Если первые символы одинаковы, система переходит ко вторым символам. Именно поэтому строка "100" идет раньше, чем "12", а "23" оказывается раньше, чем "3".

Для строк это абсолютно правильное поведение (именно так сортируются слова в словаре). Но для чисел, представленных в виде строк, это приводит к хаосу. Чтобы сортировка работала математически корректно, данные обязательно должны иметь тип Число.

Решение 1: Правильная типизация данных (Самый надежный способ)

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

Если вы используете Табличную часть объекта (в Конфигураторе):

Откройте свойства реквизита вашей табличной части в конфигураторе и убедитесь, что в поле «Тип» указано Число с необходимой длиной и точностью, а не Строка.

Если вы динамически создаете Таблицу Значений в коде:

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


// Создаем описание типов для числа (15 знаков всего, 2 знака после запятой)
МассивТипов = Новый Массив;
МассивТипов.Добавить(Тип("Число"));
КвалификаторыЧ = Новый КвалификаторыЧисла(15, 2);
ОписаниеТипаЧисло = Новый ОписаниеТипов(МассивТипов, , , КвалификаторыЧ);

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

Если данные приходят из внешнего источника (например, текстового файла):

Обязательно используйте явное приведение типов с помощью встроенной функции Число() перед записью значения в таблицу или массив:


// Пример безопасного преобразования строкового значения в число
ЗначениеИзФайла = "263";
ЧисловоеЗначение = Число(ЗначениеИзФайла);

Решение 2: Отказ от ручных сортировок и использование Списка Значений

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

Если вам необходимо быстро отсортировать простой одномерный массив чисел, воспользуйтесь системным объектом СписокЗначений. Платформа выполняет сортировку этого объекта на уровне скомпилированного C++ кода, что работает в десятки раз быстрее любого самописного цикла.

Разберем этот алгоритм по шагам:


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

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

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

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

Решение 3: Сортировка напрямую в Табличной Части формы

Если ваши данные уже выведены на форму в табличную часть, нет никакой необходимости выгружать их в массивы для сортировки. У объекта табличной части (как на клиенте, так и на сервере) есть мощный встроенный метод Сортировать().

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


// Сортировка по одной колонке по возрастанию
Объект.ИмяТабличнойЧасти.Сортировать("ИмяКолонкиЧисло Возр");

// Сортировка по нескольким колонкам (например, сначала по Группе, затем по Числу)
Объект.ИмяТабличнойЧасти.Сортировать("Группа Возр, ИмяКолонкиЧисло Убыв");

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

Анализ обходных путей: Почему костыль с «ведущими нулями» опасен?

В ходе обсуждения на форуме прозвучало предложение форматировать числа перед сортировкой, дополняя их ведущими нулями (например, превращая число 1 в "000001", а 23 в "000023"). В таком виде лексикографическая сортировка строк действительно даст математически верный результат.

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

Вердикт: Метод с ведущими нулями применим только в редких случаях для формирования специфических кодов или артикулов. Для сортировки обычных чисел использовать его категорически не рекомендуется.

Продвинутый уровень: Использование объекта «СравнениеЗначений»

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

В таких сценариях на помощь приходит объект СравнениеЗначений. Он выполняет сравнение объектов по их внутреннему уникальному идентификатору (UUID), минуя долгое обращение к базе данных для формирования текстового представления.

Рассмотрим пример использования:


// Создаем объект сравнения
ОбъектСравнения = Новый СравнениеЗначений;

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

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

← На главную