Как правильно сортировать структурный код типа "1.2.3" в 1С?

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

При работе с данными в 1С, особенно когда мы имеем дело со структурными кодами, такими как "1.2.3", "1.11.1" или "1.02.3", часто возникает проблема с их корректной сортировкой. Стандартные механизмы сортировки в 1С (как и во многих других системах), по умолчанию, используют лексикографический (строковый) порядок. Это означает, что строки сравниваются символ за символом по их кодам (например, ASCII), что приводит к результатам, не соответствующим интуитивному "человеческому" пониманию числового порядка.

Давайте рассмотрим типичный пример из практики. Предположим, у нас есть следующий список кодов:

  1. 1.01.01
  2. 1.02.3
  3. 1.1.3
  4. 1.11.1
  5. 1.2.11

При стандартной лексикографической сортировке по возрастанию мы получим:

  1. 1.01.01
  2. 1.02.3
  3. 1.1.3
  4. 1.11.1
  5. 1.2.11

Такой порядок обусловлен тем, что символ '0' меньше '1', а '1' меньше '2'. Например, "1.02.3" будет стоять перед "1.1.3", потому что '0' (во второй части "02") меньше '1' (во второй части "1"). Аналогично, "1.11.1" окажется после "1.2.11", так как '1' (во второй части "11") меньше '2' (во второй части "2").

Однако, как мы интуитивно ожидаем, правильный порядок (естественная сортировка) должен быть следующим:

  1. 1.01.01
  2. 1.1.3
  3. 1.02.3
  4. 1.2.11
  5. 1.11.1

Такой порядок подразумевает, что числовые части кода сравниваются как целые числа, а не как отдельные символы. "1.1.3" (где вторая часть "1") должен идти перед "1.02.3" (где вторая часть "2"), а "1.2.11" (где вторая часть "2") — перед "1.11.1" (где вторая часть "11").

Для решения этой проблемы в 1С существуют несколько подходов, каждый из которых имеет свои преимущества и недостатки. Мы подробно рассмотрим каждый из них.

Подход 1: Нормализация структурного кода с помощью ведущих нулей

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

Принцип работы

Суть подхода заключается в преобразовании каждой числовой компоненты кода (например, "1", "2", "11", "01") в строку фиксированной длины, дополненную ведущими нулями. Например, если мы решили, что каждая часть кода будет занимать три символа, то:

Таким образом, код "1.2.3" будет преобразован в "001.002.003", а "1.11.1" — в "001.011.001". После такого преобразования стандартная строковая сортировка будет давать желаемый результат.

Шаги реализации

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

Пример кода на 1С

Рассмотрим, как мы можем реализовать эти функции на встроенном языке 1С.


// Функция для дополнения числа ведущими нулями до заданной длины
// Пример: ДополнитьВедущимиНулями(5, 3) вернет "005"
//         ДополнитьВедущимиНулями(123, 3) вернет "123"
//         ДополнитьВедущимиНулями(1234, 3) вернет "1234" (не обрежет, но и не дополнит)
Функция ДополнитьВедущимиНулями(Знач Число, Знач Длина) Экспорт
    Если ТипЗнч(Число) <> Тип("Число") Тогда
        Возврат СтрЗаменить(СокрЛП(Число), " ", ""); // Если не число, возвращаем как есть, очистив от пробелов
    КонецЕсли;

    ПереданноеЧисло = Число; // Сохраняем исходное число
    СтрокаЧисла = Формат(ПереданноеЧисло, "ЧГ=0"); // Преобразуем число в строку без группировки

    Если СтрДлина(СтрокаЧисла) >= Длина Тогда
        Возврат СтрокаЧисла; // Если длина уже достаточна или больше, возвращаем как есть
    Иначе
        Возврат СтрЗаполнить("0", Длина - СтрДлина(СтрокаЧисла)) + СтрокаЧисла;
    КонецЕсли;
КонецФункции

// Функция для нормализации структурного кода
// Пример: НормализоватьСтруктурныйКод("1.2.3", 3) вернет "001.002.003"
//         НормализоватьСтруктурныйКод("1.11.1", 3) вернет "001.011.001"
Функция НормализоватьСтруктурныйКод(Знач ИсходныйКод, Знач МаксДлинаСегмента = 3) Экспорт
    Если ПустаяСтрока(ИсходныйКод) Тогда
        Возврат "";
    КонецЕсли;

    МассивЧастей = СтрРазделить(ИсходныйКод, ".", Ложь);
    МассивНормализованныхЧастей = Новый Массив;

    Для Каждого ЧастьКода Из МассивЧастей Цикл
        Попытка
            ЧисловаяЧасть = Число(ЧастьКода);
            МассивНормализованныхЧастей.Добавить(ДополнитьВедущимиНулями(ЧисловаяЧасть, МаксДлинаСегмента));
        Исключение
            // Если часть не является числом, добавляем ее как есть (например, в кодах "А1.1")
            МассивНормализованныхЧастей.Добавить(ЧастьКода);
        КонецПопытки;
    КонецЦикла;

    Возврат СтрСоединить(МассивНормализованныхЧастей, ".");
КонецФункции

Применение на практике

После реализации этих функций, наиболее эффективным способом использования нормализованного кода будет хранение его в отдельном реквизите справочника или документа, к которому относится этот код (сообщения 6, 12, 13). Например, если у нас есть справочник "ВидыНоменклатуры" с реквизитом "КодСтруктуры", мы можем добавить реквизит "КодСтруктурыДляСортировки" строкового типа. При записи нового элемента или изменении "КодСтруктуры" мы будем автоматически заполнять "КодСтруктурыДляСортировки" его нормализованным значением.

Давайте посмотрим на пример обновления реквизита при записи объекта:


// В обработчике события "ПередЗаписью" объекта (например, справочника)
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    // Предположим, что "КодСтруктуры" - это наш исходный строковый реквизит
    // А "КодСтруктурыДляСортировки" - это новый реквизит для нормализованного кода
    Если ЗначениеЗаполнено(ЭтотОбъект.КодСтруктуры) Тогда
        ЭтотОбъект.КодСтруктурыДляСортировки = НормализоватьСтруктурныйКод(ЭтотОбъект.КодСтруктуры, 3);
    Иначе
        ЭтотОбъект.КодСтруктурыДляСортировки = "";
    КонецЕсли;
КонецПроцедуры

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

Преимущества и недостатки

  1. Преимущества:
    • Простота сортировки: После нормализации, сортировка становится стандартной строковой, что легко реализуется в любых механизмах 1С (запросы, динамические списки, сортировка таблиц).
    • Высокая производительность: Нормализация выполняется один раз при записи данных, а не при каждой операции сортировки. Сортировка по нормализованному полю очень быстра, особенно при использовании индексов СУБД.
    • Универсальность: Подходит для всех случаев, где требуется естественная сортировка числовых компонентов.
  2. Недостатки:
    • Требует изменения структуры данных: Необходимо добавить новый реквизит в метаданные.
    • Требует предварительной обработки существующих данных: Для уже существующих записей потребуется единоразовая обработка по заполнению нового реквизита.
    • Зависимость от максимальной длины: Выбор максимальной длины сегмента может быть критичен. Если в будущем появятся части кода, превышающие заданную максимальную длину (например, "1000" при длине сегмента 3), то сортировка снова может стать некорректной. Однако, обычно этот параметр можно оценить с достаточным запасом.

Подход 2: Сортировка "на лету" с использованием ТаблицыЗначений

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

Принцип работы

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

Шаги реализации

  1. Получение исходных данных: Загружаем список кодов (например, из запроса к справочнику) в ТаблицуЗначений.
  2. Добавление колонок для числовых частей: В созданную ТаблицуЗначений добавляем новые колонки числового типа для каждой ожидаемой части кода (например, Часть1, Часть2, Часть3). Мы должны заранее знать максимальное количество частей в коде.
  3. Разбиение кода и заполнение числовых колонок: Перебираем каждую строку ТаблицыЗначений. Для каждой строки:
    • Разбиваем исходный строковый код на части по разделителю ".".
    • Преобразуем каждую часть в число и записываем ее в соответствующую числовую колонку (Часть1, Часть2 и т.д.).
    • Если частей меньше, чем колонок, или часть не является числом, заполняем колонку нулем или пропускаем.
  4. Сортировка ТаблицыЗначений: Используем метод Сортировать() объекта ТаблицаЗначений, указывая в качестве полей сортировки наши новые числовые колонки (Часть1, Часть2, Часть3) в нужном порядке.
  5. Получение результата: После сортировки ТаблицаЗначений будет содержать данные в желаемом порядке.

Пример кода на 1С

Рассмотрим пример функции, которая принимает ТаблицуЗначений с колонкой "Код" и возвращает отсортированную ТаблицуЗначений.


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

    // 1. Создаем копию таблицы для работы
    РезультатТЗ = ИсходнаяТЗ.Скопировать();

    // 2. Добавляем колонки для числовых частей кода
    // Предполагаем, что код может иметь до 5 частей (можно настроить)
    МаксКоличествоЧастей = 5; 
    Для НомерЧасти = 1 По МаксКоличествоЧастей Цикл
        ИмяКолонки = "ЧастьКода" + НомерЧасти;
        Если РезультатТЗ.Колонки.Найти(ИмяКолонки) = Неопределено Тогда
            РезультатТЗ.Колонки.Добавить(ИмяКолонки, Тип("Число"));
        КонецЕсли;
    КонецЦикла;

    // 3. Заполняем числовые колонки
    Для Каждого СтрокаТЗ Из РезультатТЗ Цикл
        КодСтроки = СтрокаТЗ.Код;
        Если ПустаяСтрока(КодСтроки) Тогда
            Продолжить;
        КонецЕсли;

        МассивЧастей = СтрРазделить(КодСтроки, ".", Ложь);
        
        Для Индекс = 0 По Мин(МассивЧастей.ВВерхнейГранице(), МаксКоличествоЧастей - 1) Цикл
            ИмяКолонки = "ЧастьКода" + (Индекс + 1);
            Попытка
                СтрокаТЗ[ИмяКолонки] = Число(МассивЧастей[Индекс]);
            Исключение
                СтрокаТЗ[ИмяКолонки] = 0; // В случае ошибки преобразования (например, нечисловая часть)
            КонецПопытки;
        КонецЦикла;
    КонецЦикла;

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

    // 5. Удаляем временные колонки, если они больше не нужны
    Для НомерЧасти = 1 По МаксКоличествоЧастей Цикл
        ИмяКолонки = "ЧастьКода" + НомерЧасти;
        РезультатТЗ.Колонки.Удалить(ИмяКолонки);
    КонецЦикла;

    Возврат РезультатТЗ;
КонецФункции

// Пример использования:
// Запрос = Новый Запрос;
// Запрос.Текст = "ВЫБРАТЬ Код ИЗ Справочник.Номенклатура";
// ИсходныеДанные = Запрос.Выполнить().Выгрузить();
// ОтсортированныеДанные = СортироватьПоСтруктурномуКоду(ИсходныеДанные);
// Для Каждого Строка Из ОтсортированныеДанные Цикл
//     Сообщить(Строка.Код);
// КонецЦикла;

Преимущества и недостатки

  1. Преимущества:
    • Не требует изменения метаданных: Мы работаем с временными данными в оперативной памяти.
    • Работает с "как есть" данными: Можно применять к любым выборкам, не требуя предварительной нормализации.
    • Гибкость: Можно настроить количество частей кода для сортировки.
  2. Недостатки:
    • Нагрузка на производительность: Каждая операция сортировки включает в себя разбиение строк и преобразование типов, что может быть медленным для больших объемов данных.
    • Потребление памяти: Для больших таблиц значений может потребоваться значительный объем оперативной памяти.
    • Сложность кода: Требует написания дополнительного кода для каждой сортировки.

Подход 3: Реализация алгоритма естественной сортировки (Natsort)

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

Принцип работы

В основе естественной сортировки лежит покомпонентное сравнение. Для двух сравниваемых строк алгоритм выполняет следующие действия:

  1. Разделение на компоненты: Каждая строка сначала разбивается на последовательность компонентов, которые могут быть либо числами, либо строковыми частями. Например, "1.02.3" может быть разбит на [1, ".", 2, ".", 3]. "file-10" будет разбит на ["file-", 10].
  2. Покомпонентное сравнение: Затем эти списки компонентов сравниваются элемент за элементом:
    • Если сравниваемые компоненты являются числами, они сравниваются как числовые значения.
    • Если сравниваемые компоненты являются строками, они сравниваются лексикографически.
    • Если типы компонентов различаются (например, число и строка), определяется правило их сравнения (обычно число считается меньше строки).
  3. Определение порядка: Результат первого несовпадающего сравнения определяет порядок исходных строк.

В 1С нет встроенной функции для естественной сортировки, но мы можем реализовать ее на встроенном языке.

Шаги реализации

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

Пример кода на 1С

Реализация естественной сортировки в 1С более сложна и объемна. Мы рассмотрим основные блоки, которые нам понадобятся.

1. Функция для разделения строки на компоненты

Эта функция будет извлекать из строки последовательности цифр и не-цифр.


// Вспомогательная функция для разделения строки на числовые и строковые компоненты
// Пример: "1.02.3" -> [1, ".", 2, ".", 3]
// Пример: "Строка10" -> ["Строка", 10]
Функция РазделитьНаКомпоненты(Знач СтрокаКода) Экспорт
    МассивКомпонентов = Новый Массив;
    ТекущаяПозиция = 1;
    ДлинаСтроки = СтрДлина(СтрокаКода);

    Пока ТекущаяПозиция <= ДлинаСтроки Цикл
        Символ = Сред(СтрокаКода, ТекущаяПозиция, 1);
        
        Если СтрНайти("0123456789", Символ) > 0 Тогда // Если символ - цифра
            НачалоЧисла = ТекущаяПозиция;
            Пока ТекущаяПозиция <= ДлинаСтроки И СтрНайти("0123456789", Сред(СтрокаКода, ТекущаяПозиция, 1)) > 0 Цикл
                ТекущаяПозиция = ТекущаяПозиция + 1;
            КонецЦикла;
            ЧисловаяЧасть = Сред(СтрокаКода, НачалоЧисла, ТекущаяПозиция - НачалоЧисла);
            МассивКомпонентов.Добавить(Число(ЧисловаяЧасть)); // Добавляем число
        Иначе // Если символ - не цифра
            НачалоСтроки = ТекущаяПозиция;
            Пока ТекущаяПозиция <= ДлинаСтроки И СтрНайти("0123456789", Сред(СтрокаКода, ТекущаяПозиция, 1)) = 0 Цикл
                ТекущаяПозиция = ТекущаяПозиция + 1;
            КонецЦикла;
            СтроковаяЧасть = Сред(СтрокаКода, НачалоСтроки, ТекущаяПозиция - НачалоСтроки);
            МассивКомпонентов.Добавить(СтроковаяЧасть); // Добавляем строковую часть
        КонецЕсли;
    КонецЦикла;

    Возврат МассивКомпонентов;
КонецФункции
2. Функция сравнения двух кодов (пользовательский компаратор)

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


// Функция-компаратор для естественной сортировки двух структурных кодов
// Возвращает:
//   -1, если Код1 < Код2
//    0, если Код1 = Код2
//    1, если Код1 > Код2
Функция СравнитьСтруктурныеКодыЕстественно(Знач Код1, Знач Код2) Экспорт
    Если Код1 = Код2 Тогда
        Возврат 0;
    КонецЕсли;
    Если ПустаяСтрока(Код1) Тогда
        Возврат -1; // Пустая строка меньше заполненной
    КонецЕсли;
    Если ПустаяСтрока(Код2) Тогда
        Возврат 1;  // Заполненная строка больше пустой
    КонецЕсли;

    МассивКомпонентов1 = РазделитьНаКомпоненты(Код1);
    МассивКомпонентов2 = РазделитьНаКомпоненты(Код2);

    Индекс1 = 0;
    Индекс2 = 0;

    Пока Истина Цикл
        Компонент1 = Неопределено;
        Если Индекс1 <= МассивКомпонентов1.ВВерхнейГранице() Тогда
            Компонент1 = МассивКомпонентов1[Индекс1];
        КонецЕсли;

        Компонент2 = Неопределено;
        Если Индекс2 <= МассивКомпонентов2.ВВерхнейГранице() Тогда
            Компонент2 = МассивКомпонентов2[Индекс2];
        КонецЕсли;

        Если Компонент1 = Неопределено И Компонент2 = Неопределено Тогда
            Возврат 0; // Коды равны, достигли конца обоих
        ИначеЕсли Компонент1 = Неопределено Тогда
            Возврат -1; // Код1 короче Код2, но части совпали до этого
        ИначеЕсли Компонент2 = Неопределено Тогда
            Возврат 1;  // Код1 длиннее Код2, но части совпали до этого
        КонецЕсли;
        
        Тип1 = ТипЗнч(Компонент1);
        Тип2 = ТипЗнч(Компонент2);

        Если Тип1 = Тип("Число") И Тип2 = Тип("Число") Тогда
            Если Компонент1 < Компонент2 Тогда
                Возврат -1;
            ИначеЕсли Компонент1 > Компонент2 Тогда
                Возврат 1;
            КонецЕсли;
        ИначеЕсли Тип1 = Тип("Строка") И Тип2 = Тип("Строка") Тогда
            Если Компонент1 < Компонент2 Тогда
                Возврат -1;
            ИначеЕсли Компонент1 > Компонент2 Тогда
                Возврат 1;
            КонецЕсли;
        Иначе
            // Сравнение разнотипных компонентов: число всегда "меньше" строки
            Если Тип1 = Тип("Число") Тогда // Число1 vs Строка2
                Возврат -1;
            Иначе // Строка1 vs Число2
                Возврат 1;
            КонецЕсли;
        КонецЕсли;

        Индекс1 = Индекс1 + 1;
        Индекс2 = Индекс2 + 1;
    КонецЦикла;
КонецФункции
3. Использование функции сравнения для сортировки

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

Например, мы можем перенести наши объекты в Массив, который содержит объекты с реквизитом "Код", и реализовать сортировку "пузырьком" или "быстрой сортировкой", используя нашу функцию СравнитьСтруктурныеКодыЕстественно().


// Пример использования компаратора для сортировки МассиваСтрок
Функция ОтсортироватьМассивКодов(Знач МассивКодов) Экспорт
    // Простейшая сортировка пузырьком для демонстрации
    Для И1 = 0 По МассивКодов.ВВерхнейГранице() Цикл
        Для И2 = И1 + 1 По МассивКодов.ВВерхнейГранице() Цикл
            Если СравнитьСтруктурныеКодыЕстественно(МассивКодов[И1], МассивКодов[И2]) = 1 Тогда
                // Меняем местами, если первый больше второго
                ВременнаяПеременная = МассивКодов[И1];
                МассивКодов[И1] = МассивКодов[И2];
                МассивКодов[И2] = ВременнаяПеременная;
            КонецЕсли;
        КонецЦикла;
    КонецЦикла;
    Возврат МассивКодов;
КонецФункции

// Пример:
// ИсходныйМассив = Новый Массив;
// ИсходныйМассив.Добавить("1.01.01");
// ИсходныйМассив.Добавить("1.02.3");
// ИсходныйМассив.Добавить("1.1.3");
// ИсходныйМассив.Добавить("1.11.1");
// ИсходныйМассив.Добавить("1.2.11");
//
// ОтсортированныйМассив = ОтсортироватьМассивКодов(ИсходныйМассив);
// Для Каждого Код Из ОтсортированныйМассив Цикл
//     Сообщить(Код);
// КонецЦикла;

Преимущества и недостатки

  1. Преимущества:
    • Высокая гибкость: Не требует изменения структуры данных и позволяет сортировать данные в любой момент "на лету" без предварительной подготовки.
    • Точность: Обеспечивает наиболее корректную естественную сортировку для любых типов структурных кодов, включая те, что содержат нечисловые части (например, "A.1.B.2").
    • Имитирует человеческое понимание: Результат сортировки максимально соответствует интуитивным ожиданиям.
  2. Недостатки:
    • Сложность реализации: Требует написания довольно объемного и сложного кода, который нужно тщательно тестировать.
    • Производительность: При каждой операции сортировки выполняется разбиение строк, преобразование типов и покомпонентное сравнение. Это может быть медленнее, чем сортировка по заранее нормализованному полю, особенно для очень больших объемов данных.
    • Ограничения встроенного языка: Отсутствие прямого механизма "пользовательского компаратора" для стандартных методов сортировки коллекций 1С может потребовать реализации собственной сортировки.

Рекомендации по проектированию и вводу данных

Помимо технических решений для сортировки, крайне важно учитывать и качество исходных данных. Многие проблемы с сортировкой возникают из-за непоследовательного или некорректного формирования структурных кодов на этапе их ввода или генерации. В сообщениях форума (5, 7) справедливо отмечается, что за коды "01" и "1" на одном уровне "надо отрывать кое что кое кому", подчеркивая важность единообразия.

Для предотвращения проблем с сортировкой изначально, мы рекомендуем следовать следующим правилам при проектировании и вводе структурных кодов:

  1. Единообразие форматирования числовых частей: Если в коде предполагаются числовые сегменты, всегда используйте фиксированную длину с ведущими нулями, если это логически оправдано. Например, если максимальное значение сегмента не превысит 99, используйте двухзначный формат ("01", "02", ..., "99"). Если до 999, то трехзначный ("001", "002", ..., "999"). Это автоматически сделает код "самосортирующимся" лексикографически.
  2. Обучение пользователей: Информируйте пользователей о правилах формирования кодов и объясняйте, почему важно их соблюдать.
  3. Автоматическая генерация кодов: По возможности, генерируйте структурные коды программно, чтобы исключить ошибки ручного ввода и обеспечить единообразие форматирования. Например, при создании нового элемента, система сама должна предложить следующий код в правильном формате (например, "001.002.003").
  4. Валидация при вводе: Реализуйте проверки на корректность формата кода при его вводе пользователем.

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

Таким образом, мы рассмотрели три основных подхода к решению проблемы некорректной сортировки структурного кода в 1С. Выбор конкретного подхода зависит от требований к производительности, объему данных, возможности изменения структуры метаданных и сложности требуемой реализации. В большинстве случаев, для часто используемых кодов, хранение нормализованного кода в отдельном реквизите является наиболее оптимальным решением. Если же требуется гибкость и работа с данными "на лету" без изменения структуры, можно прибегнуть к сортировке через ТаблицуЗначений или реализации алгоритма естественной сортировки.

← На главную