Алгоритм синхронизации (сравнения) двух таблиц (по текстовому полю) (1Cv8)

Материал из КинтВики
Перейти к: навигация, поиск


Источник

Автор статьи: vde69

Редакторы: Гений 1С, Волшебник, Alter72

Последняя редакция №8 от 18.09.08

URL: http://kb.mista.ru/article.php?id=129

Ключевые слова: синхронизация, динамических, таблиц, алгоритм, сравнение, строк

v8: Алгоритм синхронизации (сравнения) двух таблиц (по текстовому полю)

В процессе обмена данными часто возникает вопрос синхронизации двух динамических таблиц по одному полю. Для небольших объемов информации вполне подходит и простой перебор всех вариантов (двойной цикл, или рекурсия). Но для больших массивов (более 10 000 элементов) это становиться очень медленно. Предлагаю использовать другой алгоритм, основанный на одном цикле, в моем случае это дало ускорение в х800!!!

Для начала рассмотрим общий принцип:

  1. Надо получить две таблицы (в моем случае ДанныеФайла и ВсеТовары), процесс получения таблиц здесь не рассматривается
  2. Предварительная обработка строк индекса, приведение к одному регистру, удаление пробелов, другое форматирование, это здесь тоже не рассматривается
  3. Сортировка таблиц по индексу
  4. Параллельная обработка двух таблиц

Теперь собственно пример:

// сравнивает по символьно строки, возвращает истина если 
// Строка1 больше чем Строка2
Функция СтрокаБольше(Строка1, Строка2)
    Результат = Ложь;
    
    Длина = Макс(СтрДлина(Строка1),СтрДлина(Строка2));
    Для Индекс = 1 По Длина Цикл
        Если Индекс > СтрДлина(Строка2)Тогда
            // если дошли до сюда, значит строка1 длинее строки2
            Результат = Истина;
            Прервать;
        ИначеЕсли Индекс > СтрДлина(Строка1)Тогда
            // ну а в этом случае короче, а значит меньше
            Результат = Ложь;
            Прервать;
        КонецЕсли;
        
        // сравнение по коду символа не работает, поэтому сравниваем по символьно
        // символ можно получать и по другому, 
// но этот вариант у меня работает быстрее

        Код1 = Символ(КодСимвола(Строка1, Индекс));
        Код2 = Символ(КодСимвола(Строка2, Индекс));
        Если Код1 < Код2 Тогда
            // все, дальше можно не смотреть, попался больший символ
            Результат = Ложь;
            Прервать;
        ИначеЕсли Код1 > Код2 Тогда
            // все, дальше можно не смотреть, попался меньший символ
            Результат = Истина;
            Прервать;
        КонецЕсли;
    КонецЦикла;
    
    Возврат Результат;
КонецФункции

Процедура Выполнить()
    
    ВсеТовары.Сортировать  ("Артикул Возр");
    ДанныеФайла.Сортировать("Артикул Возр");

             
    Результат = Новый ТаблицаЗначений;
    Результат.Колонки.Добавить( "Номенклатура", Справочники.Номенклатура);

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


Вот собственно и все.

От Гения 1С: Другой вариант решения задачи здесь Книга знаний: v8: Сравнение двух таблиц значений с ключемыми полями

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