Почему в объекте Соответствие меняется порядок элементов и как обеспечить его сохранение

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

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

Природа объекта Соответствие: почему порядок не гарантируется

Разберем ситуацию, описанную в вопросе. Программист ожидает, что коллекция будет вести себя как список, сохраняя последовательность ввода. Однако Соответствие в 1С — это классическая реализация ассоциативного массива на базе хеш-таблицы (или сбалансированного дерева по хеш-кодам ключей). Рассмотрим основные причины отсутствия порядка:

  1. Механизм хеширования. При добавлении элемента в Соответствие платформа вычисляет хеш-код ключа. На основе этого значения определяется местоположение элемента во внутренней структуре памяти (в так называемых «корзинах» или бакетах). Порядок обхода коллекции — это просто технический обход этих внутренних структур. Хеш-код строки «Банки» может быть больше хеш-кода строки «Склады», поэтому они встают не по алфавиту и не по времени добавления.
  2. Рехеширование при изменении размера. Это именно то, что произошло в примере автора, когда добавление ключа _СистемыНалогообложения изменило весь порядок. Хеш-таблицы имеют свойство динамически расширяться. Когда количество элементов достигает определенного порога (коэффициент заполнения), система выделяет новый блок памяти и перераспределяет все существующие элементы. В этот момент «визуальный» порядок в цикле Для каждого может измениться до неузнаваемости.
  3. Отсутствие индексации. В отличие от объекта Массив или ТаблицаЗначений, у Соответствия нет метода Получить(Индекс). Если к элементу нельзя обратиться по порядковому номеру, это явный сигнал разработчику: платформа не берет на себя обязательств по хранению физической последовательности.

Сравнение со Структурой

Часто возникает вопрос: почему Структура иногда кажется более упорядоченной? Рассмотрим различия:

Как реализовать коллекцию с сохранением порядка

Если в вашей задаче критично знать, в какой последовательности добавлялись данные, проанализируем три основных способа решения проблемы.

Способ 1: Использование пары Массив + Соответствие

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

Рассмотрим пример реализации:


// Создаем структуры данных
ОчередьКлючей = Новый Массив;
Данные = Новый Соответствие;

// Добавляем элементы
НовыйКлюч = "ПоступлениеТоваровУслуг";
Если Данные.Получить(НовыйКлюч) = Неопределено Тогда
    ОчередьКлючей.Добавить(НовыйКлюч);
КонецЕсли;
Данные.Вставить(НовыйКлюч, "Значение 1");

НовыйКлюч = "_СистемыНалогообложения";
Если Данные.Получить(НовыйКлюч) = Неопределено Тогда
    ОчередьКлючей.Добавить(НовыйКлюч);
КонецЕсли;
Данные.Вставить(НовыйКлюч, "Значение 2");

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

Способ 2: Использование Таблицы Значений

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

Проанализируем пример:


ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Ключ");
ТЗ.Колонки.Добавить("Значение");

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

НоваяСтрока = ТЗ.Добавить();
НоваяСтрока.Ключ = "_Склады";
НоваяСтрока.Значение = "Центральный склад";

// Обход гарантированно вернет элементы в порядке добавления
Для Каждого Стр Из ТЗ Цикл
    Сообщить(Стр.Ключ);
КонецЦикла;

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

Способ 3: Список значений

Если вам нужно просто хранить список уникальных или неуникальных значений с представлением и сохранением порядка, используйте СписокЗначений. Он поддерживает методы Добавить() и Вставить(Индекс, ...), что позволяет четко контролировать позицию элемента.

Выясним причину странного поведения с нижним подчеркиванием

Вернемся к вопросу автора: почему именно символ _ вызвал такой эффект? В программировании строки часто сравниваются по кодам символов. Символ подчеркивания имеет код, отличный от букв алфавита, что влияет на результат хеш-функции. При вставке такого ключа произошло переполнение текущей емкости хеш-таблицы, что спровоцировало процедуру рехеширования. Все элементы «переехали» в новые ячейки памяти в соответствии с новой логикой распределения, что и отразилось на выводе в Сообщить().

Резюме и рекомендации

Подведем итоги нашего исследования работы с коллекциями в 1С:

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

← На главную