Долой дубли!

Публикация № 17093

Разработка - Практика программирования

7
Мало кто поспорит с тем,  что компактный и красивый код повышает настроение, а громоздкий и неуникальный - наоборот.
Простой метод исключения дублирования кода в одном из часто используемых алгоритмов.

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

Традиционный способ:
1. Сортируем ТЗ по этим колонкам с данными для шапки (назовем их ключами)
2. Перебираем ТЗ и по мере смены ключей создаем новый/записываем предыдущий документ для заполнения
3. После перебора проверяем и записываем документ.

ТЗ.Сортировать("Ключ_1,Ключ_2,...,Ключ_N");
ТЗ.ВыбратьСтроки();
Пока ТЗ.ПолучитьСтроку() = 1 Цикл 
  Если ТЗ.НомерСтроки = 1 Тогда
    // БЛОК 1 Создать новый документ
    // БЛОК 2 Заполнить заголовок документа
  ИначеЕсли	(ТЗ.Ключ_1 <> ПредЗначение_Ключ_1) ИЛИ
            (ТЗ.Ключ_2 <> ПредЗначение_Ключ_2) ИЛИ
            ...
            (ТЗ.Ключ_N <> ПредЗначение_Ключ_N) Тогда
    // сменились ключи			
    // БЛОК 3 Заполнить подвал документа
    // БЛОК 4 Записать / вывести документ 

    // БЛОК 1 Создать новый документ !дублируем код!
    // БЛОК 2 Заполнить заголовок документа !дублируем код!
  КонецЕсли;
  // БЛОК 5 Заполнение строки спецификации документа

  ПредЗначение_Ключ_1 = ТЗ.Ключ_1; 
  ПредЗначение_Ключ_2 = ТЗ.Ключ_2;
  ...
  ПредЗначение_Ключ_N = ТЗ.Ключ_N;
КонецЦикла;
// БЛОК 3 Заполнить подвал документа !дублируем код!
// БЛОК 4 Записать / вывести документ !дублируем код!


Тот же алгоритм применяется при группировке и выводе данных из ТЗ в печатную форму.

"Копипасте" кода - вешь нехорошая, неэстетичная, и даже бы сказал отбивающая желание заниматься этим делом вообще, а если еще этот код будут читать другие...
Можно, конечно, все это вывести в процедуры, но тогда в них надо передать массу параметров, что не совсем удобно.

Первое, и самое простое, что можно сделать - добавить и перестроить условия в цикле ( комментарии (6) Tarasenkov и (10) Orefkov ) :

ПредЗначение_Ключ_1	= ПолучитьПустоеЗначение();
ПредЗначение_Ключ_2	= ПолучитьПустоеЗначение();
...
ПредЗначение_Ключ_N	= ПолучитьПустоеЗначение();

ТЗ.Сортировать("Ключ_1,Ключ_2,...,Ключ_N");
ТЗ.НоваяСтрока();
ТЗ.ВыбратьСтроки();
Пока ТЗ.ПолучитьСтроку() = 1 Цикл 
  Если (ТЗ.Ключ_1 <> ПредЗначение_Ключ_1) ИЛИ
       (ТЗ.Ключ_2 <> ПредЗначение_Ключ_2) ИЛИ
       ...
       (ТЗ.Ключ_N <> ПредЗначение_Ключ_N) ИЛИ (ТЗ.НомерСтроки = 1) Тогда
    Если ТЗ.НомерСтроки > 1 Тогда
      // БЛОК 3 Заполнить подвал документа
      // БЛОК 4 Записать / вывести документ
    КонецЕсли;
    Если ТЗ.НомерСтроки = ТЗ.КоличествоСтрок() Тогда
      Прервать;
    КонецЕсли;
    // БЛОК 1 Создать новый документ
    // БЛОК 2 Заполнить заголовок документа
  КонецЕсли;
  // БЛОК 5 Заполнение строки спецификации документа

  ПредЗначение_Ключ_1 = ТЗ.Ключ_1; 
  ПредЗначение_Ключ_2 = ТЗ.Ключ_2;
  ...
  ПредЗначение_Ключ_N = ТЗ.Ключ_N;
КонецЦикла; 
ТЗ.УдалитьСтроку(ТЗ.КоличествоСтрок());


Вариант poppy (комментарий (23)) c избавлением от нагромождения условий и самым простым кодом: достигается вынесением в функцию чтения и сравнения ключей двух соседних записей:

                                        
// ПроверитьСтрокуТаблицы(<ТЗ>,<СписокКлючей>)
// 
// функция проверяет достижение текущей строки ТЗ ее последней записи, 
// или несовпадение значений по списку колонок в текущей и следующей записи, возвращает:
// 1 в случае выполнения условий, 0 - иначе.
// Параметры:
// <ТЗ>             - таблица значений
// <СписокКлючей>   - список значений - идентификаторов сравниваемых колонок

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

Применение функции:
СтрокаКолонок = "Ключ_1,Ключ_2,...,Ключ_N";
СписокКлючей = СоздатьОбъект("СписокЗначений");
СписокКлючей.ИзСтрокиСРазделителями("""" + СтрЗаменить(СтрокаКолонок, ",", """,""") + """");
   	
Флаг = 1;
ТЗ.Сортировать(СтрокаКолонок);
ТЗ.ВыбратьСтроки();
Пока ТЗ.ПолучитьСтроку() = 1 Цикл 
  Если Флаг = 1 Тогда
    // БЛОК 1 Создать новый документ
    // БЛОК 2 Заполнить заголовок документа
  КонецЕсли;
  // БЛОК 5 Заполнение строки спецификации документа
  Флаг = ПроверитьСтрокуТаблицы(ТЗ, СписокКлючей);
  Если Флаг = 1 Тогда
    // БЛОК 3 Заполнить подвал документа
    // БЛОК 4 Записать / вывести документ
  КонецЕсли;
КонецЦикла;

Просто и понятно.

Метод автора, на момент появления статьи описывался здесь в ед. числе.
Он заключается в предварительном прогоне таблицы с проверкой условий и заполнением двух новых колонок в ТЗ с значениями-индикаторами о создании и записи документа.

// ИзмененияКлючейТЗ(<ТЗ>,<СтрокаКолонок>,<ИмяКолонкиНач>,<ИмяКонКолонкиКон>)
//
// Процедура выполняет сравнение значений в указанных колонках ТЗ в соседних записях и 
// записывает результат сравнения  в две добавляемые колонки 
//
// ТЗ             - таблица значений
// СтрокаКолонок  - Строка колонок (ключей) через запятую, по которым сравниваются значения между соседними записями
// ИмяКолонкиНач  - Имя добавляемой в ТЗ первой колонки, необязательное 
//   (если не задано, обращение к ней возможно по номеру "1") . 
//   В данную колонку заносится число, результат сравнения текущей и предыдущей записи, 
//   а именно, ближайший номер колонки (по порядку из <СтрокаКолонок>), по которой 
//   значения в указанных записях не совпадают; 0 если несовпадений нет. 
// ИмяКолонкиКон	- Имя добавляемой в ТЗ второй колонки, необязательное 
//   (если не задано, обращение к ней возможно по номеру "1")
//   В данную колонку заносится число, результат сравнения текущей и следующей записи, 
//   а именно, ближайший номер колонки (по порядку из <СтрокаКолонок>), по которой 
//   значения в указанных записях не совпадают; 0 если несовпадений нет. 

Процедура ИзмененияКлючейТЗ(ТЗ,Знач СтрокаКолонок,Знач ИмяКолонкиНач = "",Знач ИмяКолонкиКон = "")
  Перем ИДКолонок[10]; // идентификаторы колонок-ключей 
  Перем Ключи[10];     // значения ключей
  Перем КолКлючей;     // количество ключей          
  Перем М1,М2;
  Перем КолСтрокТЗ;  
  Перем ПромЗнач;
   
  КолСтрокТЗ = ТЗ.КоличествоСтрок();

  Если КолСтрокТЗ > 0 Тогда
    СтрокаКолонок = СтрЗаменить(СтрокаКолонок,",",РазделительСтрок);
    КолКлючей = СтрКоличествоСтрок(СтрокаКолонок);

    // получить идентификаторы колонок
    Для М1 = 1 По КолКлючей Цикл
      ИДКолонок[М1] = СтрПолучитьСтроку(СтрокаКолонок,М1);
    КонецЦикла;

    ТЗ.ВставитьКолонку(ИмяКолонкиНач,1);
    ТЗ.ВставитьКолонку(ИмяКолонкиКон,2);

    ТЗ.Заполнить(0,,,"1,2");

    ТЗ.УстановитьЗначение(1,1,1); 	// начало в 1-й записи
    ТЗ.УстановитьЗначение(КолСтрокТЗ,2,1);	// конец в последней

    // заполнить ключи по первой записи
    Для М1 = 1 По КолКлючей Цикл
      Ключи[М1] = ТЗ.ПолучитьЗначение(1,ИДКолонок[М1]);
    КонецЦикла;

    // начинаем сравнение со второй по последнюю
    Для М2 = 2 По КолСтрокТЗ Цикл

      М1 = 1;
      Пока М1 <=КолКлючей Цикл
        ПромЗнач = ТЗ.ПолучитьЗначение(М2,ИДКолонок[М1]);
        Если ПромЗнач   <> Ключи[М1] Тогда
          ТЗ.УстановитьЗначение(М2 - 1,2,М1); // конец старой группировки в пред записи
          ТЗ.УстановитьЗначение(М2    ,1,М1); // начало новой группировки в текущей записи 
          // обновим оставшиеся ключи 
          Ключи[М1]   = ПромЗнач;
          М1 = М1 + 1;
          Пока М1 <= КолКлючей Цикл
            Ключи[М1] = ТЗ.ПолучитьЗначение(М2,ИДКолонок[М1]);
            М1 = М1 + 1;
          КонецЦикла;
          Прервать;
        КонецЕсли;     
        М1 = М1 + 1;
      КонецЦикла;               
    КонецЦикла;
  КонецЕсли;
КонецПроцедуры                        

Процедура отрабатывает сравнение ключей полностью, с указанием номера несовпадающей колонки-ключа.
Получилось не совсем кратко, вследствие оптимизации, зато использование очень компактное:
СтрокаКолонок = "Ключ_1,Ключ_2,...,Ключ_N";	
ТЗ.Сортировать(СтрокаКолонок);
ИзмененияКлючейТЗ(ТЗ,СтрокаКолонок,"Нач","Кон");
	
ТЗ.ВыбратьСтроки();
Пока ТЗ.ПолучитьСтроку() = 1 Цикл 
  Если ТЗ.Нач > 0 Тогда
    // БЛОК 1 Создать новый документ 
    // БЛОК 2 Заполнить заголовок документа 
  КонецЕсли;
  // БЛОК 5 Заполнение строки спецификации документа
  Если ТЗ.Кон > 0 Тогда
    // БЛОК 3 Заполнить подвал документа
    // БЛОК 4 Записать документ 
  КонецЕсли;
КонецЦикла;


Оригинальный способ указан int3 (комментарий (3)). Он заключается в создании вспомогательной таблицы индексов, которая представляет из себя исходную ТЗ, свернутую по колонкам-ключам с суммированием количества записей. (изменено оформление).
// СоздатьИндексТЗ(<ТЗ>,<СтрокаКолонок>,<ИмяИндексКолонки>)
// функция возвращает свернутую таблицу значений по указанным колонкам 
// с суммированием количества записей в добавляемой колонке
// параметры: 
// ТЗ               - таблица значений для свертки
// СтрокаКолонок    - строка колонок, разделенных запятыми, для свертки.
// ИмяИндексКолонки - добавляемая колонка №1, в которой суммируется количество записей.

Функция СоздатьИндексТЗ(ТЗ,СтрокаКолонок,Знач ИмяИндексКолонки	= "")
  Перем ТЗИндекс;
  ТЗИндекс  = СоздатьОбъект("ТаблицаЗначений");
  Если ТЗ.КоличествоСтрок()  > 0 Тогда
    ТЗ.Выгрузить(ТЗиндекс,,,СтрокаКолонок);      

    ТЗИндекс.ВставитьКолонку(ИмяИндексКолонки,1);
    ТЗИндекс.Заполнить(1,,,"1");
    ТЗИндекс.Свернуть(СтрокаКолонок,"1");
    ТЗИндекс.Сортировать(СтрокаКолонок,1);
  КонецЕсли;
  Возврат ТЗИндекс;
КонецФункции


Применение таблицы значений - "индекса":
СтрокаКолонок = "Ключ_1,Ключ_2,...,Ключ_N";	
ТЗ.Сортировать(СтрокаКолонок);

ТЗИндекс = СоздатьИндексТЗ(ТЗ,СтрокаКолонок,"Кол");
ТЗИндекс.ВыбратьСтроки();

ТЗ.ВыбратьСтроки();
Пока ТЗИндекс.ПолучитьСтроку()  = 1 Цикл
  // БЛОК 1 Создать новый документ 
  // БЛОК 2 Заполнить заголовок документа 
  Для М1 = 1 По ТЗИндекс.Кол Цикл
    ТЗ.ПолучитьСтроку();
    // БЛОК 5 Заполнение строки спецификации документа
  КонецЦикла;
  // БЛОК 3 Заполнить подвал документа
  // БЛОК 4 Записать документ 
КонецЦикла;


Автор выражает благодарность Poppy, Int3, Tarasenkov, Orefkov за активное участие в статье.

P.S. О быстродействии.
Самый быстрый, - это метод Int3. Он выигрывает у традиционного при средней длине "спецификации" от 50-ти строк ("2% шапок"), или по 1 строке в 98% случаях.
Метод автора дает к традиционному от +50 до +130%.
Но даже сотня процентов дает очень незначительный прирост по времени, - "голые" циклы и условия (сравнивалось на них) на 100т записях прогоняются за секунды, так что красота, удобочитаемость и универсальность кода того ст'оит
 
Изменения от 16.03.2009
 
Еще один метод, с хранением всех новых документов в списке значений и общей записью документов вне цикла

                                        
// ОбщийКлюч(<ТЗ>,<СписокКлючей>)
// 
// функция формирует и возвращает общий строковый ключ по значениям из текущей строки ТЗ, 
// по переданному списку колонок
// Параметры:
// <ТЗ>             - таблица значений
// <СписокКлючей>   - список значений - идентификаторов колонок

Функция ОбщийКлюч(ТЗ, СписокКлючей)
  Перем НомСтр;
  Перем М1;
  Перем ТекКлюч;
  НомСтр = ТЗ.НомерСтроки;
  ТекКлюч = ЗначениеВСтрокуВнутр(  ТЗ.ПолучитьЗначение(НомСтр,
                                                      СписокКлючей.ПолучитьЗначение(1)));
  Для М1 = 2 По СписокКлючей.РазмерСписка()  Цикл
     ТекКлюч = ТекКлюч +  
                 ЗначениеВСтрокуВнутр(   ТЗ.ПолучитьЗначение(НомСтр ,
                                                      СписокКлючей.ПолучитьЗначение(М1)));
  КонецЦикла;
  Возврат 0;
КонецФункции

Применение функции:
СтрокаКолонок = "Ключ_1,Ключ_2,...,Ключ_N";
СписокКлючей = СоздатьОбъект("СписокЗначений");
СписокНовДок = СоздатьОбъект("СписокЗначений");
СписокКлючей.ИзСтрокиСРазделителями("""" + СтрЗаменить(СтрокаКолонок, ",", """,""") + """");
   	
ТЗ.ВыбратьСтроки();
Пока ТЗ.ПолучитьСтроку() = 1 Цикл 
  ТекКлюч = ОбщийКлюч(ТЗ, СписокКлючей);
  НовДок = СписокНовДок.Получить(ТекКлюч);
  Если ТипЗначенияСтр(НовДок) = "Документ" Тогда
    // БЛОК 1 Создать новый документ в НовДок с использованием СоздатьОбъект()
    // БЛОК 2 Заполнить заголовок документа НовДок
    СписокНовДок.Установить(ТекКлюч, НовДок);
  КонецЕсли;
  // БЛОК 5 Заполнение строки спецификации документа НовДок
КонецЦикла;
Для М1 = 1 По СписокНовДок.РазмерСписка() Цикл
    НовДок = СписокНовДок.ПолучитьЗначение(М1);
      // БЛОК 3 Заполнить подвал документа НовДок
      // БЛОК 4 Записать / вывести документ НовДок
КонецЦикла;


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

Специальные предложения

Комментарии
Избранное Подписка Сортировка: Древо
1. CheBurator 12.01.08 20:31 Сейчас в теме
неэстетично...
имхается проще и красивше рекурсивную процедуру заюзать...
8. Shaman100M 1191 14.01.08 09:57 Сейчас в теме
(1) (2) Рекурсивная, скорее всего, на сравнение и заполнение строк ТЧ. Иногда может получиться громоздко, т.к. нужно хранить / передавать в процедуру(ы) ключи и все, что там необходимо будет сделать. Я попытался реализовать одной вспомогательной универсальной процедурой с четко определенными параметрами.
(3) +1 хороший индекс! Единственное, добавил бы после свертки ТЗИндекс
Код
 ТЗИндекс.Сортировать(СтрокаКолонок); // Сортировка после Свернуть() может сбиться. 
Показать полностью
14. int3 14.01.08 13:57 Сейчас в теме
(8) Согласен, никто не гарантирует порядка после свертки, правда ни разу не сталкивался с такой ситуацией :-/ (Хотя в реальных алгоритмах дополнительную сортировку включаю в код - надежность дороже ;-) )
(12) такой индекс даст прирост производительности на больших объемах данных, т.е. когда сложность условия в цикле превысит накладные расходы на индексирование, т.е. к примеру при десятке ключей на сотне тысяч записей
ну или иначе - при варировании ключевых условий, тут уже выйдет на первое место гибкость :-/
17. Shaman100M 1191 14.01.08 16:30 Сейчас в теме
(14) при десятке ключей на сотне т: минус 40%
2. poppy 3352 12.01.08 21:18 Сейчас в теме
Как-то уж очень мудрено...

Самый простой способ избавиться от дублей - использовать процедуры. Ведь они именно для этого придуманы?
3. int3 13.01.08 23:22 Сейчас в теме
Если есть желание сэкономить число сравнений, почему бы не построить индекс? Например так:
Код
СтрокаКолонок = "Ключ_1,Ключ_2,...,Ключ_N";   
ТЗ.Сортировать(СтрокаКолонок);
ТЗиндекс = СоздатьОбъект("ТаблицаЗначений");
ТЗ.Выгрузить(ТЗиндекс,,,СтрокаКолонок);
ИндексКолонка = ТЗиндекс.КоличествоКолонок()+1;
ТЗиндекс.КоличествоКолонок(ИндексКолонка);
ТЗиндекс.Заполнить(1,,,ИндексКолонка);
ТЗиндекс.Свернуть(СтрокаКолонок,ИндексКолонка);
ТЗ.ВыбратьСтроки();
РазмерБлока = 0;
НомерБлока = 0;
Пока ТЗ.ПолучитьСтроку() = 1 Цикл
    Если РазмерБлока=0 Тогда
      НомерБлока = НомерБлока + 1;
      РазмерБлока = ТЗиндекс.ПолучитьЗначение(НомерБлока,ИндексКолонка);
        // БЛОК 1 Создать новый документ 
        // БЛОК 2 Заполнить заголовок документа 
    КонецЕсли;
    // БЛОК 5 Заполнение строки спецификации документа
   РазмерБлока = РазмерБлока - 1;
    Если РазмерБлока=0 Тогда
        // БЛОК 3 Заполнить подвал документа
        // БЛОК 4 Записать документ 
    КонецЕсли;
КонецЦикла;
Показать полностью

всяко пошустрее будет
Shaman100M; +1 Ответить
15. int3 14.01.08 14:26 Сейчас в теме
> 3 ключа, значения от 1 до 10:
> (3) +400%
> мой: +180%

Кстати, очень интересный результат. На что ушло время?
16. Shaman100M 1191 14.01.08 15:41 Сейчас в теме
(15) Замерял не в отладчике, а с пом. _GetPerformanceCounter() . Отладчик показывает +100% Максимум времени ушло на Свернуть()
18. int3 15.01.08 08:30 Сейчас в теме
(16) хм... Такая картина - несовпадение результатов разных методов замера наверное объясняется "особенностями" работы платформы, в частности уборщика мусора.
(17) т.е. сфера применения у него найдется, и не только в плане "красивости" кода? буду рад, если пригодится :)
когда-то на проклабе обнаружил конкурс на самый быстрый метод удаления строк из ТЗ (правда он к тому времени уже закончился), заинтересовался и написал свой вариант с использованием такого индексирования - занятный вариант получился, но не без "особенностей" :)
20. Shaman100M 1191 15.01.08 12:49 Сейчас в теме
(18) да, полезный конкурс, столько особенностей при оптимизации обнаружилось, вплоть до наличия запятой в НоваяКолонка() :)
(19) )))) Ну тогда какое-нить другое красивое слово.
21. Shaman100M 1191 15.01.08 12:53 Сейчас в теме
(18) если не против, добавлю в статью с ссылкой.
22. int3 15.01.08 13:53 Сейчас в теме
4. tarasenkov 14.01.08 09:06 Сейчас в теме
А не проще написать так:
Код
Если (ТЗ.НомерСтроки    = 1) ИЛИ
(ТЗ.Ключ_1<>ПредЗначение_Ключ_1) ИЛИ
(ТЗ.Ключ_2<>ПредЗначение_Ключ_2) ИЛИ
...
(ТЗ.Ключ_N<>ПредЗначение_Ключ_N) Тогда

Если (ТЗ.НомерСтроки    = 1) Тогда
        // БЛОК 1 Создать новый документ !дублируем код!
        // БЛОК 2 Заполнить заголовок документа !дублируем код!
Иначе
        // сменились ключи         
        // БЛОК 3 Заполнить подвал документа
        // БЛОК 4 Записать / вывести документ 
КонецЕсли;

КонецЕсли;
Показать полностью

При этом никакого дублирования кода нет,
и удобочитаемость остается.
9. Shaman100M 1191 14.01.08 10:10 Сейчас в теме
(4) (5) (6) от объединения условий отказался, - можно запутаться в условиях. Блоки 3 и 4 всегда должны идти после блока 5 (для текущего документа), их дублирования условиями не избежать. Если добавлять фиктивную строку, - необходимо проверить/задать уникальные ключи для нее.
5. tarasenkov 14.01.08 09:09 Сейчас в теме
И почему нельзя редактировать комментарии?
Я имел ввиду такой код:

Если (ТЗ.НомерСтроки = 1) ИЛИ
(ТЗ.Ключ_1<>ПредЗначение_Ключ_1) ИЛИ
(ТЗ.Ключ_2<>ПредЗначение_Ключ_2) ИЛИ
...
(ТЗ.Ключ_N<>ПредЗначение_Ключ_N) Тогда
// БЛОК 1 Создать новый документ
// БЛОК 2 Заполнить заголовок документа
Если (ТЗ.НомерСтроки > 1) Тогда
// сменились ключи
// БЛОК 3 Заполнить подвал документа
// БЛОК 4 Записать / вывести документ
КонецЕсли;
КонецЕсли;
6. tarasenkov 14.01.08 09:15 Сейчас в теме
* и предварительного просмотра нет - тоже плохо :(
Итак.
Код
Если (ТЗ.НомерСтроки = 1) ИЛИ
(ТЗ.Ключ_1<>ПредЗначение_Ключ_1) ИЛИ
(ТЗ.Ключ_2<>ПредЗначение_Ключ_2) ИЛИ
...
(ТЗ.Ключ_N<>ПредЗначение_Ключ_N) Тогда
   Если (ТЗ.НомерСтроки > 1) Тогда
      // сменились ключи 
      // БЛОК 3 Заполнить подвал документа
      // БЛОК 4 Записать / вывести документ 
   КонецЕсли;
   // БЛОК 1 Создать новый документ
   // БЛОК 2 Заполнить заголовок документа
КонецЕсли;
Показать полностью


Дублирование записи документа/вывода печатной формы после цикла не так страшно.
Хотя тоже можно избежать добавив в таблицу фиктивную последнюю строку.
Shaman100M; +1 Ответить
12. Shaman100M 1191 14.01.08 12:21 Сейчас в теме
Замерил время выполнения, 10т записей
традиционный, (6) (10) 100%

3 ключа, значения от 1 до 100:
(3) от +40% до +50%
мой: от +250 до +300%

3 ключа, значения от 1 до 10:
(3) +400%
мой: +180%

1 ключ, значения от 1 до 10, от 1 до 100
(3) от + 20% до +40%
мой: +130%

Ст'оит ли красота времени?
7. begemot 268 14.01.08 09:17 Сейчас в теме
Как оригинальный вариант решения имеет право на существование...
Shaman100M; +1 Ответить
10. orefkov 1975 14.01.08 10:56 Сейчас в теме
Я бы это сделал так:
Код
ПредЗначение_Ключ_1   = ПолучитьПустоеЗначение(99);
ПредЗначение_Ключ_2   = ПолучитьПустоеЗначение(99);
...
ПредЗначение_Ключ_N   = ПолучитьПустоеЗначение(99);

ТЗ.Сортировать("Ключ_1,Ключ_2,...,Ключ_N");
ТЗ.НоваяСтрока();
ТЗ.ВыбратьСтроки();
Пока ТЗ.ПолучитьСтроку() = 1 Цикл 
    Если (ТЗ.Ключ_1<>ПредЗначение_Ключ_1) ИЛИ
      (ТЗ.Ключ_2<>ПредЗначение_Ключ_2) ИЛИ
      ...
      (ТЗ.Ключ_N<>ПредЗначение_Ключ_N) Тогда
      Если ТЗ.НомерСтроки > 1 Тогда
           // БЛОК 3 Заполнить подвал документа
           // БЛОК 4 Записать / вывести документ
      КонецЕсли;
      Если ТЗ.НомерСтроки = ТЗ.КоличествоСтрок() Тогда
         Прервать;
      КонецЕсли;
        // БЛОК 1 Создать новый документ
        // БЛОК 2 Заполнить заголовок документа
    КонецЕсли;
    // БЛОК 5 Заполнение строки спецификации документа
      
    ПредЗначение_Ключ_1   = ТЗ.Ключ_1; 
    ПредЗначение_Ключ_2   = ТЗ.Ключ_2;
    ...
    ПредЗначение_Ключ_N   = ТЗ.Ключ_N;
КонецЦикла;

Показать полностью
Shaman100M; +1 Ответить
11. Shaman100M 1191 14.01.08 11:41 Сейчас в теме
(10) а если ТЗ.ПолучитьЗначение(1,"Ключ_1") = ПолучитьПустоеЗначение() ?
19. orefkov 1975 15.01.08 09:57 Сейчас в теме
(11)
Ну, сделай
ключ1 = "bcad7cf3-2fd3-4286-a654-139b37840a79"
13. Shaman100M 1191 14.01.08 12:43 Сейчас в теме
Хотя мож и стоит. Сравнивается с голым циклом с парой-тройкой условий и присваиваний.
23. poppy 3352 16.01.08 11:37 Сейчас в теме
Внесу свои пять копеек в решение задачи "Простой метод исключения дублирования кода в одном из часто используемых алгоритмов."

Код
Функция ПроверитьСтрокуТаблицы(ТЗ, НомерСтроки, СписокКлючей)
   
   Если НомСтр < 1 Тогда
       Возврат 1;
   КонецЕсли;
   
   Если НомСтр >= ТЗ.КоличествоСтрок() Тогда
       Возврат 1;
   КонецЕсли;
   
   Для ии = 1 По СписокКлючей.РазмерСписка() Цикл
      Колонка = СписокКлючей.ПолучитьЗначение(СписокКлючей.РазмерСписка() - ии + 1);
      Если не (ТЗ.ПолучитьЗначение(НомерСтроки, Колонка) = ТЗ.ПолучитьЗначение(НомерСтроки + 1, Колонка)) Тогда
          Возврат 1;
      КонецЕсли;
   КонецЦикла;
   
   Возврат 0;
   
КонецФункции


   СтрокаКолонок = "Ключ_1,Ключ_2,...,Ключ_N";
   
   СписокКлючей = СоздатьОбъект("СписокЗначений");
   СписокКлючей.ИзСтрокиСРазделителями("""" + СтрЗаменить(СтрокаКолонок, ",", """,""") + """");

      ТЗ.Сортировать(СтрокаКолонок);
      
   Флаг = 1;

   ТЗ.ВыбратьСтроки();
   Пока ТЗ.ПолучитьСтроку() = 1 Цикл 
      
      Если Флаг = 1 Тогда
         // БЛОК 1 Создать новый документ
         // БЛОК 2 Заполнить заголовок документа
      КонецЕсли;
      
      // БЛОК 5 Заполнение строки спецификации документа
      
      Флаг = ПроверитьСтрокуТаблицы(ТЗ, ТЗ.НомерСтроки, СписокКлючей);
   
      Если Флаг = 1 Тогда
         // БЛОК 3 Заполнить подвал документа
         // БЛОК 4 Записать / вывести документ
      КонецЕсли;
      
   КонецЦикла;
Показать полностью


Очевидно, что представленный код работает медленнее, чем при индексировании. Но ведь речь идет о простоте и понятности алгоритма и кода? Не так ли?
magics; Shaman100M; +2 Ответить
30. maloi_a 24.01.08 09:49 Сейчас в теме
(23)
Внесу свою копейку.
В Функции ПроверитьСтрокуТаблицы(ТЗ, СписокКлючей)
надо добавить объявление локальных переменных НомСтр и М1.
Перем НомСтр и М1;
Иначе может поменять глобальные переменные с такими именами.
31. poppy 3352 24.01.08 09:59 Сейчас в теме
(30) Правильное замечание.

В (23) вкралась ошибка. В условиях вместо НомСтр должно быть написано НомерСтроки.

Получается, что локальными переменными нужно объявлять: Перем ии, Колонка.
32. Shaman100M 1191 24.01.08 10:07 Сейчас в теме
(30) нашел, таки, но про колонку забыл. ;)
Правило про переменные, - это классика. Стараюсь его выполнять. Ну, вряд ли кто-то додумается сделать глобальные переменные с такими короткими и простыми именами, но вероятность есть. Обычно добавляется префикс "гл".
(31) (23) в статье скорректировано, ошибка с НомСтр изначально была устранена. Кстати, зачем передавался НомерСтроки ?
33. poppy 3352 25.01.08 00:19 Сейчас в теме
(32)
> Кстати, зачем передавался НомерСтроки ?

Наверно, для бОльшей универсальности. Ведь можно написать и так:

Код
ТЗ.ВыбратьСтроки();
Пока ТЗ.ПолучитьСтроку() = 1 Цикл 
   Если ПроверитьСтрокуТаблицы(ТЗ, ТЗ.НомерСтроки - 1, СписокКлючей) = 1 Тогда
      // БЛОК 1 Создать новый документ
      // БЛОК 2 Заполнить заголовок документа
   КонецЕсли;
   
   // БЛОК 5 Заполнение строки спецификации документа
   
   Если ПроверитьСтрокуТаблицы(ТЗ, ТЗ.НомерСтроки, СписокКлючей) = 1 Тогда
      // БЛОК 3 Заполнить подвал документа
      // БЛОК 4 Записать / вывести документ
   КонецЕсли;
КонецЦикла;
Показать полностью
34. Shaman100M 1191 26.01.08 18:09 Сейчас в теме
24. Shaman100M 1191 17.01.08 08:54 Сейчас в теме
25. poppy 3352 17.01.08 11:33 Сейчас в теме
(24)
Я не против.

Можно еще описать решение (6). Считаю, что оно вполне справляется с поставленной в статье задаче.

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

З.Ы. Попробуй длинный комментарий к процедуре ИзмененияКлючейТЗ() сделать в несколько строк, а то он у меня на экран не помещается - неудобно читать статью. :-(
26. Shaman100M 1191 17.01.08 14:49 Сейчас в теме
(25) насчет (6) ( и (10) ) да, подсознательно фильтровал универсальные, но для полной картины включу. Можно, в принципе и его сделать универсальным, вынеся операции сравнения и присваивания в функции.
По комментарию - разве он у тебя не переносится на след. строки? Хотя, при копировании в конфигуратор лучше, чтобы строки были короткие.
27. poppy 3352 18.01.08 02:45 Сейчас в теме
(26)
> По комментарию - разве он у тебя не переносится на след. строки?

Есть ощущение, что строки внутри конструкции ( code ) ( /code) не переносятся... :( В IE7

Но это претензия скорее к саппорту, чем к тебе. Сделай опиcание ИмяКолонкиНач и ИмяКолонкиКон в несколько строк, возможно, будет лучше...

З.Ы.
Решение описанное в (10) не стоит внимания, потому-что неправильное.
28. Shaman100M 1191 18.01.08 10:42 Сейчас в теме
(27) Чем оно неправильное? Решения (6) и (10) - одно и тоже, просто (10) дописано до конца, а в (6) код + идея.
29. poppy 3352 18.01.08 16:52 Сейчас в теме
(28)
Да, действительно, решение (10) правильное. Я невнимательно его прочтала. Приношу извинения перед автором за напрасный поклеп. ;)
35. Shaman100M 1191 16.03.09 19:41 Сейчас в теме
Оставьте свое сообщение

См. также

Приватный блокчейн и 1С популярно 5

Статья no Нет файла Бесплатно (free) Практика программирования Блокчейн

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

02.09.2019    1528    mkalimulin    140       

Кодогенерация и метагенерация в 1С 24

Статья Программист Нет файла Бесплатно (free) Практика программирования Математика и алгоритмы Разработка

В своем докладе на конференции INFOSTART EVENT 2018 EDUCATION Дмитрий Белозеров рассказал о разработке инструмента, позволяющего программно работать с метаданными 1С и писать скрипты для выполнения тех же действий, которые выполняет разработчик в конфигураторе –  с какими сложностями и нюансами пришлось столкнуться, и что получилось в итоге.

26.08.2019    4000    kirovsbis    28       

Интеграция сценарного тестирования в процесс разработки 81

Статья Программист Нет файла Бесплатно (free) Практика программирования Разработка

Разработчик системы «Тестер» Дмитрий Решитко в своем докладе на конференции INFOSTART EVENT 2018 EDUCATION показывает, что процесс тестирования можно очень плотно интегрировать в процесс разработки, что внедрение тестирования – это возможность развития программиста как такового, позволяющая ему упорядочивать ход мыслей и оставаться «в фокусе». Навыки построения процесса кодирования на стыке с тестированием сокращают время на концентрацию, освобождают от страха перед изменениями и улучшают память разработчика.

08.07.2019    4446    grumagargler    7       

Управляй качеством кода 1С с помощью SonarQube 221

Статья Программист Нет файла Россия Бесплатно (free) Практика программирования Разработка

Управляй техническом долгом проектов 1С с помощью SonarQube. В статье рассматривается пример применения SonarQube при разработке.

07.07.2019    16190    olegtymko    191       

Выгрузка документа по условию 5

Статья Программист Нет файла v8 Бесплатно (free) Практика программирования Разработка

Что делать, если документы нужно выгружать не все подряд, а по какому-то фильтру: статусу, дате, набору условий... А что если он соответствовал этим условиям, а потом перестал? А если потом опять начал? Такие ситуации заставили попотеть не одного программиста.

25.04.2019    4872    m-rv    2       

Как прикрутить ГУИД к регистру сведений 23

Статья Программист Нет файла v8 Бесплатно (free) Практика программирования Перенос данных из 1C8 в 1C8 Разработка

... и немного теории обмена данными. В частности, разберем боль всех, кто пишет небанальные обмены данными: как набору записей регистра сведений назначить гуид и далее использовать его в обмене для идентификации этого набора.

16.04.2019    7413    m-rv    16       

О времени и 1С 206

Статья Программист Нет файла Бесплатно (free) Практика программирования Разработка

Основы и особенности работы со временем в 1С. Как избавиться от боли при работе в разных часовых поясах. Что такое момент времени. И другое.

01.04.2019    15305    YPermitin    58       

Пример создания bridge (http api - tcp) для ККТ "Касса №1" ("К1-Ф") 5

Статья Системный администратор Программист Нет файла Россия Кассовые операции Бесплатно (free) Практика программирования Разработка ККМ

Пример создания bridge (http api - tcp) для ККТ "Касса №1" ("К1-Ф"). Данная статья будет полезна интеграторам, программистам, тем кто работает (интегрирует, разрабатывает) различное ТО либо железки. Версия и релиз технологической платформы не имеет значения.

17.03.2019    2987    dmarenin    0       

Быстрее чем INSERT! BULK-операции и примеры использования 112

Статья Системный администратор Программист Нет файла Бесплатно (free) Производительность и оптимизация (HighLoad) Практика программирования Разработка Внешние источники данных Перенос данных из 1C8 в 1C8

Microsoft SQL Server поддерживает так называемые BULK-операции, используемые для быстрого изменения больших объемов данных в базе. В статье пойдет речь о практических примерах их использования. Все примеры сделаны в контексте платформы 1С (а как иначе).

09.03.2019    9820    YPermitin    38       

Как писать понятные коммиты 67

Статья Программист Нет файла Россия Бесплатно (free) Практика программирования Разработка

Как писать сообщения коммитов так, чтобы потом не было мучительно больно.

06.03.2019    7842    Scorpion4eg    34       

Расширяем свой багаж 2

Статья Программист Нет файла Бесплатно (free) Практика программирования Разработка

Алгоритм решения возможной нетиповой задачи на собеседовании.

29.01.2019    3308    scientes    15       

Подготовка ребёнка* к ЕГЭ по информатике. Часть четвертая 4

Статья Программист Нет файла Бесплатно (free) Практика программирования Разработка

Решение систем логических уравнений повышенного уровня сложности.

25.01.2019    3068    vasilev2015    0       

Подготовка ребенка* к ЕГЭ по информатике. Часть вторая 2

Статья Программист Нет файла Бесплатно (free) Практика программирования

Примеры на Паскале. Если сам родитель* - поддержи ! Если сам водила - посигналь !

19.01.2019    3328    vasilev2015    0       

Подготовка к ЕГЭ сына - школьника (по информатике) 9

Статья Программист Нет файла Бесплатно (free) Практика программирования

Примеры на Паскале. Если сам отец - поддержи ! Если сам водила - посигналь !

17.01.2019    3821    vasilev2015    50       

Быстрая отладка экранных форм документов и справочников 19

Статья Программист Нет файла Бесплатно (free) Практика программирования

Трюк элементарный и я думаю, что большинство моих коллег владеет им, но для тех, кто не знает, он может сэкономить большое количество времени.

18.12.2018    4609    milkers    19       

1С + asterisk (автоматический обзвон) часть 1 38

Статья Системный администратор Программист Нет файла Россия Бесплатно (free) Практика программирования WEB Телефония, SIP

Пример реализации автообзвона (с обработкой ответа на отвечающей стороне) с использованием ami asterisk. Данная статья может быть полезна программистам, интеграторам, администраторам. Версия и релиз технологической платформы не имеет значения.

29.11.2018    7274    dmarenin    9       

Автоматические и управляемые блокировки применительно к типовым конфигурациям 1С 126

Статья Программист Нет файла v8 v8::blocking 1cv8.cf Бесплатно (free) Математика и алгоритмы Практика программирования

Основные принципы работы с режимами автоматических и управляемых блокировок в 1С Предприятие 8. Теория и применение в типовых конфигурациях: БП, УТ, ЕРП

10.11.2018    20905    ids79    40       

Развитие 1С программиста 51

Статья Программист Нет файла Бесплатно (free) Практика программирования Личная эффективность

Делюсь своим опытом и видением развития 1С программиста.

17.10.2018    13607    pashamak    62       

Вспомогательные инструкции в коде 1С 104

Статья Программист Нет файла v8 1cv8.cf Бесплатно (free) Практика программирования

Помогаем редактору кода 1С помогать нам писать и анализировать код.

15.10.2018    20523    tormozit    100       

Записки про metadata.js 53

Статья Программист Нет файла Бесплатно (free) Практика программирования

Отличительные особенности разработки на metadata.js

31.07.2018    9138    1c-intelligence    59       

Учебный курс. Повышение качества разработки. Ошибки программы 97

Статья Программист Нет файла Бесплатно (free) Практика программирования Математика и алгоритмы Рефакторинг и качество кода

Учебный курс по теории и практике программирования. Бесплатно. В виде структурированного текста. Лекции № 3,4,5. Эти лекции посвящены ошибкам программ, их классификации и способам исправления

10.07.2018    15812    Артано    92       

Автоматизируй это! 149

Статья Системный администратор Программист Нет файла Бесплатно (free) Практика программирования

Здравствуйте. Меня зовут Виталий Онянов. Я работаю в компании ФТО. Мы занимаемся внедрением и поддержкой ERP-систем, в том числе и на 1С. Сегодня я хотел бы поделиться нашим опытом автоматизации своих задач и рассказать о том, какие регламентные задания мы настраиваем на серверах наших клиентов. Возможно, кому-то покажется, что это совсем простые и очевидные вещи, но я в своей работе периодически вижу разработчиков, которые делают какие-то задачи руками изо дня в день, и мне бы хотелось донести до них мысль о том, что многие из этих задач можно и нужно автоматизировать.

02.07.2018    16155    Tavalik    12       

Повышаем эффективность разработки правил обмена 124

Статья Программист Нет файла v8 КД ОС Бесплатно (free) Практика программирования Перенос данных из 1C8 в 1C8

Как повысить скорость и качество разработки правил обмена? Как вести групповую разработку правил обмена? Как облегчить сопровождение правил обмена после передачи в эксплуатацию? Об этом и многом другом вы можете узнать из этой статьи.

25.06.2018    19351    olegtymko    47       

Как сделать запрос на изменение данных 75

Статья Программист Нет файла v8 v8::Запросы 1cv8.cf Бесплатно (free) Практика программирования

В статье приведены особенности внутренней архитектуры и примеры работы с расширением языка запросов 1С.

01.06.2018    21239    m-rv    21       

Учебный курс. Повышение качества разработки. Вводная лекция, часть 2 49

Статья Программист Нет файла Бесплатно (free) Практика программирования Математика и алгоритмы

Учебный курс по теории и практике программирования. Бесплатно. В виде структурированного текста. Лекция №2. Эта лекция посвящена абстракциям, их свойствами и практическому применению в рамках классических парадигм программирования.

24.05.2018    10724    Артано    36       

Строим графы средствами 1С (без GraphViz) 42

Статья Программист Нет файла v8 Бесплатно (free) Практика программирования

Множество статей на Инфостарте описывают, как работать с компонентой GraphViz, чтобы построить ориентированный граф. Но практически нет материалов, как работать с такими графами средствами 1С. Сегодня я расскажу, как красиво строить графы с минимальным пересечением. Нам этот метод пригодился для отрисовки алгоритмов в БИТ.Финансе, т.к. типовой механизм не устраивал. Еще это может быть полезно для визуализации различных зависимостей: расчета себестоимости, графы аффилированности компаний и т.д. Надеюсь, эта статья поможет сделать мир 1С красивее и гармоничней:) Итак, поехали...

23.05.2018    17012    slozhenikin_com    19       

Распределение расходов пропорционально продажам 9

Статья Программист Пользователь Нет файла v8 v8::ОУ УТ10 УУ Финансовый учет и бюджетирование (FRP) Учет доходов и расходов Бесплатно (free) Практика программирования

Финансовая модель. Распределение административных расходов по подразделениям пропорционально продажам за месяц. Дополнительные реквизиты против бизнес-процессов!

13.05.2018    11385    Rustig    9       

Велостыли: Регламентные задания 15

Статья Программист Нет файла Россия Бесплатно (free) Практика программирования

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

09.05.2018    10278    dsdred    28       

Веб-разработка на 1Script. Глава 2 64

Статья Программист Нет файла Бесплатно (free) Практика программирования WEB

Продолжение учебника по веб-разработке с помощью фреймворка Oscript.Web. Структура приложения, основные объекты, URL-маршрутизация, универсальная консоль серверов 1С.

22.04.2018    12097    Evil Beaver    27       

Доброе программирование, или сказки для программистов 8

Статья Программист Нет файла Бесплатно (free) Практика программирования

Я попробовал составить список хорошего и доброго, что помогает читающему код жить легче. Возможно, остальные программисты меня поддержат))

03.03.2018    6219    Gladkov_Anton    9       

Минимализмы 3 351

Статья Программист Нет файла v8 Бесплатно (free) Практика программирования Универсальные функции

Очередная серия "минимализмов" [http://infostart.ru/public/306536/, https://infostart.ru/public/460935/]. Также, как и в предыдущих статьях, здесь приведена подборка коротких оригинальных авторских решений некоторых задач. Ранее эти решения были разбросаны по моим комментариям к чужим публикациям.

19.02.2018    35660    ildarovich    44       

Веб-разработка на 1Script. Глава 1 250

Статья Программист Нет файла Бесплатно (free) Практика программирования

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

12.02.2018    25598    Evil Beaver    97       

Версионирование правил обмена в Git 64

Статья Программист Нет файла Windows Бесплатно (free) Практика программирования

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

15.12.2017    12977    bforce    22