Разработка и Конфигурация · 11 мин
Как сравнить два списка значений в 1С
Практические способы сравнения двух списков значений в 1С: поэлементное сравнение, поиск различий, вложенные циклы и таблицы значений. Примеры кода и типичные ошибки.
Сравнение двух списков значений — типовая задача при разработке на платформе 1С:Предприятие. Она возникает при проверке изменений данных, синхронизации справочников, контроле состава табличных частей документов и при обмене данными между базами. В зависимости от цели нужно либо просто установить факт совпадения списков, либо получить конкретные отличающиеся элементы.
Ключевой момент, который часто упускают: объект «СписокЗначений» в 1С не поддерживает прямое сравнение оператором «=». Попытка написать Если Список1 = Список2 Тогда не даст корректного результата — сравниваются ссылки на объекты, а не их содержимое. Поэтому сравнение всегда выполняется программно: перебором элементов, через вспомогательные структуры или путём преобразования списков в другие коллекции.
Выбор метода зависит от трёх условий: важен ли порядок элементов, нужно ли учитывать представления и пометки, а также каков объём данных. Для списков из десятков элементов подойдёт простой перебор, для тысяч записей разумнее использовать соответствия или таблицы значений — иначе вложенные циклы дадут заметную просадку производительности.
Что учитывать перед сравнением списков
Прежде чем писать код, определите, что именно считается «равенством» списков в вашей задаче. Элемент списка значений содержит четыре свойства: значение, представление, пометку и картинку. В большинстве прикладных задач сравнивают только значения, но если список пришёл из формы выбора с пометками, состояние флажков тоже может быть значимым.
Второй вопрос — порядок следования элементов. Списки [А, Б, В] и [В, Б, А] содержат одинаковые значения, но при поэлементном сравнении по индексу окажутся «разными». Если порядок не важен, перед сравнением списки стоит отсортировать или использовать методы, нечувствительные к порядку.
Третий момент — дубликаты. Список значений допускает повторяющиеся элементы. Если в первом списке значение встречается дважды, а во втором один раз, формально списки различны, хотя набор уникальных значений совпадает. Определите заранее, нужно ли контролировать кратность вхождений.
Какие свойства элемента значимы для задачи
Нужна ли предварительная сортировка списков
Сравнивать наборы или точные последовательности
От этого зависит выбор алгоритма
Поэлементное сравнение в цикле
Самый простой способ проверить идентичность двух списков — сравнить количество элементов, а затем последовательно пройти по индексам. Метод подходит, когда порядок элементов гарантированно одинаков, например оба списка сформированы одним и тем же алгоритмом.
Функция СпискиРавны(Список1, Список2)
Если Список1.Количество() <> Список2.Количество() Тогда
Возврат Ложь;
КонецЕсли;
Для Инд = 0 По Список1.Количество() - 1 Цикл
Если Список1[Инд].Значение <> Список2[Инд].Значение Тогда
Возврат Ложь;
КонецЕсли;
КонецЦикла;
Возврат Истина;
КонецФункции
Обратите внимание на индексацию с нуля: первый элемент списка имеет индекс 0, поэтому цикл идёт до Количество() - 1. Распространённая ошибка — начать цикл с единицы, что приводит к пропуску первого элемента или к выходу за границы списка.
Если нужно сравнивать и пометки, добавьте внутрь цикла проверку Список1[Инд].Пометка <> Список2[Инд].Пометка. Аналогично для представлений. Однако помните: представление может формироваться автоматически и отличаться даже при одинаковых значениях, поэтому сравнивать его стоит только при явной необходимости.
Сравнение без учёта порядка элементов
Когда порядок не важен, есть два рабочих подхода. Первый — отсортировать оба списка методом СортироватьПоЗначению() и затем применить поэлементное сравнение из предыдущего раздела. Способ прост, но меняет исходные списки, что не всегда допустимо.
Второй подход — для каждого элемента первого списка искать совпадение во втором через метод НайтиПоЗначению(). Если хотя бы один элемент не найден, списки различны. Проверку нужно выполнять в обе стороны или предварительно сравнить количество элементов, иначе список [А, Б] окажется «равен» списку [А, Б, В].
Функция НаборыСовпадают(Список1, Список2)
Если Список1.Количество() <> Список2.Количество() Тогда
Возврат Ложь;
КонецЕсли;
Для Каждого Элемент Из Список1 Цикл
Если Список2.НайтиПоЗначению(Элемент.Значение) = Неопределено Тогда
Возврат Ложь;
КонецЕсли;
КонецЦикла;
Возврат Истина;
КонецФункции
Как получить различия между списками
На практике чаще требуется не факт «равны/не равны», а конкретный ответ: какие элементы добавились, какие удалены. Для этого формируют два результирующих списка: элементы, присутствующие только в первом списке, и элементы, присутствующие только во втором.
Алгоритм строится на двух проходах. Первый цикл перебирает первый список и отбирает элементы, которых нет во втором — это «удалённые» относительно второго списка. Второй цикл делает зеркальную проверку и находит «добавленные». Оба результата можно вывести пользователю или использовать для дальнейшей обработки.
// Элементы, которые есть в Список1, но отсутствуют в Список2
ТолькоВПервом = Новый СписокЗначений;
Для Каждого Элемент Из Список1 Цикл
Если Список2.НайтиПоЗначению(Элемент.Значение) = Неопределено Тогда
ТолькоВПервом.Добавить(Элемент.Значение);
КонецЕсли;
КонецЦикла;
Для наглядного представления различий удобно вывести оба списка в табличный документ или в таблицу значений на форме с колонками «Только в первом», «Только во втором», «В обоих». Это стандартный приём для инструментов сверки данных между базами или периодами.
- 1Проверьте, что оба списка заполнены и имеют ожидаемый тип значений
- 2Первым циклом найдите элементы, которые есть только в первом списке
- 3Вторым циклом найдите элементы, которые есть только во втором списке
- 4Сформируйте отчёт: добавленные, удалённые, совпадающие элементы
- 5Проверьте результат на тестовом примере с известными различиями
Ускорение сравнения больших списков
Метод НайтиПоЗначению() выполняет линейный поиск, поэтому сравнение двух списков по несколько тысяч элементов вложенным перебором работает медленно: сложность растёт как произведение размеров списков. Для больших объёмов применяют соответствия или таблицы значений.
Приём с соответствием: значения первого списка выгружаются в соответствие как ключи, затем элементы второго списка проверяются через Соответствие[Значение] — доступ по ключу выполняется быстро. Аналогично можно выгрузить оба списка в таблицы значений и соединить их запросом с полным соединением, получив различия одним запросом.
Индекс = Новый Соответствие;
Для Каждого Элемент Из Список1 Цикл
Индекс.Вставить(Элемент.Значение, Истина);
КонецЦикла;
Для Каждого Элемент Из Список2 Цикл
Если Индекс[Элемент.Значение] = Неопределено Тогда
// Элемент есть только во втором списке
КонецЕсли;
КонецЦикла;
Вариант с запросом особенно удобен, когда значения — ссылки, и по ним нужно сразу получить дополнительные реквизиты для отчёта. Таблицы значений помещаются во временные таблицы, а полное соединение с проверкой на NULL даёт обе категории различий за одно обращение.
Сравнение подходов
Простой код, подходит для малых списков и когда важен порядок. Медленный на больших объёмах.
Не требует сортировки, удобен для поиска различий. Квадратичная сложность — не для тысяч элементов.
Быстрый поиск по ключу, хорош для больших списков. Требует дополнительной памяти и контроля дубликатов.
Оптимален для сверки с выводом отчёта и получением реквизитов ссылок. Код сложнее, нужен запрос.
Типичные ошибки при сравнении списков
Самая частая ошибка — попытка сравнить списки оператором равенства. Второе место занимает сравнение без учёта типов: строка «123» и число 123 — разные значения, и списки окажутся неравными, хотя визуально совпадают. Перед сравнением убедитесь, что типы значений в обоих списках согласованы.
Ещё одна проблема — пустые и незаполненные списки. Если переменная не инициализирована, обращение к методам вызовет ошибку. Проверяйте, что оба параметра действительно содержат списки значений, особенно когда они приходят извне: из формы, из хранилища настроек или из параметров процедуры.
Наконец, осторожности требует модификация списка внутри цикла перебора. Удаление элементов из списка, по которому идёт цикл «Для Каждого», приводит к пропуску элементов или ошибкам. Если нужно удалять — итерируйтесь по индексу в обратном порядке или собирайте элементы для удаления в отдельную коллекцию.
Проверка результата и контрольные точки
После реализации алгоритма проверьте его на контрольных примерах: идентичные списки, списки с разным порядком, списки с одним отличающимся элементом, пустые списки, списки с дубликатами. Каждый случай должен давать ожидаемый результат — это быстрый способ отловить ошибки индексации и логики.
При работе с реальными данными полезно временно выводить счётчики: сколько элементов совпало, сколько найдено только в первом и только во втором списке. Если суммы не сходятся с размерами исходных списков, в логике есть дефект — например, потеря дубликатов при использовании соответствия.
Как проверить корректность сравнения
Функция возвращает Истина, списки различий пусты
Найдены различия при заведомо равных списках
Результат соответствует требованию к порядку
Порядок влияет, хотя не должен, или наоборот
Различия корректно показывают лишние элементы
Ошибка выполнения или потеря лишних элементов
Совпавшие + только в первом = размер первого списка
Суммы не сходятся — потеряны дубликаты или элементы
Частые вопросы
Можно ли сравнить два списка значений одной строкой кода?
Нет, встроенного метода сравнения содержимого у объекта «СписокЗначений» нет. Минимальный вариант — своя функция с проверкой количества и поэлементным циклом. Такую функцию удобно вынести в общий модуль и переиспользовать во всех местах, где требуется сверка списков.
Как сравнить списки, если значения — ссылки на элементы справочника?
Ссылки сравниваются напрямую оператором равенства, это корректно: две ссылки на один и тот же объект равны. Проблемы возникают только если в одном списке ссылки, а в другом, например, строковые представления кодов — тогда нужно привести данные к единому виду перед сравнением.
Что делать, если в списках есть дубликаты и они важны?
Методы с соответствием и НайтиПоЗначению теряют информацию о кратности. Для учёта дубликатов храните в соответствии счётчик вхождений каждого значения: при обходе второго списка уменьшайте счётчик. Ненулевые остатки покажут различия с учётом количества повторов.
Как сравнить список значений с таблицей значений?
Прямого сравнения нет — это разные типы коллекций. Выгрузите колонку таблицы значений методом ВыгрузитьКолонку() в массив и загрузите его в список через ЗагрузитьЗначения(), после чего применяйте любой из описанных методов. Либо перенесите значения списка в таблицу и сравнивайте через запрос.
Почему сравнение работает медленно на больших списках?
Метод НайтиПоЗначению перебирает список линейно, поэтому вложенный цикл по двум большим спискам даёт квадратичное число операций. Замените поиск на соответствие с доступом по ключу или выполните сравнение запросом через временные таблицы — оба подхода существенно быстрее на тысячах элементов.
Что важно запомнить
Списки значений в 1С сравнивают только программно: поэлементно — когда важен порядок, через НайтиПоЗначению или соответствие — когда важен состав. Для больших объёмов используйте соответствия или запросы к таблицам значений, и всегда проверяйте алгоритм на контрольных примерах с дубликатами и разной длиной списков.