Алгоритм синхронизации (сравнения) двух таблиц (по текстовому полю) (1Cv8)
Источник
Автор статьи: vde69
Редакторы: Гений 1С, Волшебник, Alter72
Последняя редакция №8 от 18.09.08
URL: http://kb.mista.ru/article.php?id=129
Ключевые слова: синхронизация, динамических, таблиц, алгоритм, сравнение, строк
v8: Алгоритм синхронизации (сравнения) двух таблиц (по текстовому полю)
В процессе обмена данными часто возникает вопрос синхронизации двух динамических таблиц по одному полю. Для небольших объемов информации вполне подходит и простой перебор всех вариантов (двойной цикл, или рекурсия). Но для больших массивов (более 10 000 элементов) это становиться очень медленно. Предлагаю использовать другой алгоритм, основанный на одном цикле, в моем случае это дало ускорение в х800!!!
Для начала рассмотрим общий принцип:
- Надо получить две таблицы (в моем случае ДанныеФайла и ВсеТовары), процесс получения таблиц здесь не рассматривается
- Предварительная обработка строк индекса, приведение к одному регистру, удаление пробелов, другое форматирование, это здесь тоже не рассматривается
- Сортировка таблиц по индексу
- Параллельная обработка двух таблиц
Теперь собственно пример:
// сравнивает по символьно строки, возвращает истина если
// Строка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: Сравнение двух таблиц значений с ключемыми полями
Вместо СтрокаБольше() можно и для строк использовать операторы сравнения (>, =, < и тд...) Принцип сравнения тот же самый, различает большие и маленькие буквы (маленькая меньше большой).