Долой дубли!

Публикация № 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 Сейчас в теме
неэстетично...
имхается проще и красивше рекурсивную процедуру заюзать...
2. poppy 3353 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 Ответить 3
4. tarasenkov 14.01.08 09:06 Сейчас в теме
А не проще написать так:
Код
Если (ТЗ.НомерСтроки    = 1) ИЛИ
(ТЗ.Ключ_1<>ПредЗначение_Ключ_1) ИЛИ
(ТЗ.Ключ_2<>ПредЗначение_Ключ_2) ИЛИ
...
(ТЗ.Ключ_N<>ПредЗначение_Ключ_N) Тогда

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

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

При этом никакого дублирования кода нет,
и удобочитаемость остается.
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 Ответить 5
7. begemot 267 14.01.08 09:17 Сейчас в теме
Как оригинальный вариант решения имеет право на существование...
Shaman100M; +1 Ответить
8. Shaman100M 1191 14.01.08 09:57 Сейчас в теме
(1) (2) Рекурсивная, скорее всего, на сравнение и заполнение строк ТЧ. Иногда может получиться громоздко, т.к. нужно хранить / передавать в процедуру(ы) ключи и все, что там необходимо будет сделать. Я попытался реализовать одной вспомогательной универсальной процедурой с четко определенными параметрами.
(3) +1 хороший индекс! Единственное, добавил бы после свертки ТЗИндекс
Код
 ТЗИндекс.Сортировать(СтрокаКолонок); // Сортировка после Свернуть() может сбиться. 
Показать полностью
9. Shaman100M 1191 14.01.08 10:10 Сейчас в теме
(4) (5) (6) от объединения условий отказался, - можно запутаться в условиях. Блоки 3 и 4 всегда должны идти после блока 5 (для текущего документа), их дублирования условиями не избежать. Если добавлять фиктивную строку, - необходимо проверить/задать уникальные ключи для нее.
10. orefkov 1978 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 Ответить 6
11. Shaman100M 1191 14.01.08 11:41 Сейчас в теме
(10) а если ТЗ.ПолучитьЗначение(1,"Ключ_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%

Ст'оит ли красота времени?
13. Shaman100M 1191 14.01.08 12:43 Сейчас в теме
Хотя мож и стоит. Сравнивается с голым циклом с парой-тройкой условий и присваиваний.
14. int3 14.01.08 13:57 Сейчас в теме
(8) Согласен, никто не гарантирует порядка после свертки, правда ни разу не сталкивался с такой ситуацией :-/ (Хотя в реальных алгоритмах дополнительную сортировку включаю в код - надежность дороже ;-) )
(12) такой индекс даст прирост производительности на больших объемах данных, т.е. когда сложность условия в цикле превысит накладные расходы на индексирование, т.е. к примеру при десятке ключей на сотне тысяч записей
ну или иначе - при варировании ключевых условий, тут уже выйдет на первое место гибкость :-/
15. int3 14.01.08 14:26 Сейчас в теме
> 3 ключа, значения от 1 до 10:
> (3) +400%
> мой: +180%

Кстати, очень интересный результат. На что ушло время?
16. Shaman100M 1191 14.01.08 15:41 Сейчас в теме
(15) Замерял не в отладчике, а с пом. _GetPerformanceCounter() . Отладчик показывает +100% Максимум времени ушло на Свернуть()
17. Shaman100M 1191 14.01.08 16:30 Сейчас в теме
(14) при десятке ключей на сотне т: минус 40%
18. int3 15.01.08 08:30 Сейчас в теме
(16) хм... Такая картина - несовпадение результатов разных методов замера наверное объясняется "особенностями" работы платформы, в частности уборщика мусора.
(17) т.е. сфера применения у него найдется, и не только в плане "красивости" кода? буду рад, если пригодится :)
когда-то на проклабе обнаружил конкурс на самый быстрый метод удаления строк из ТЗ (правда он к тому времени уже закончился), заинтересовался и написал свой вариант с использованием такого индексирования - занятный вариант получился, но не без "особенностей" :)
19. orefkov 1978 15.01.08 09:57 Сейчас в теме
(11)
Ну, сделай
ключ1 = "bcad7cf3-2fd3-4286-a654-139b37840a79"
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 Сейчас в теме
23. poppy 3353 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 Ответить 3
24. Shaman100M 1191 17.01.08 08:54 Сейчас в теме
25. poppy 3353 17.01.08 11:33 Сейчас в теме
(24)
Я не против.

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

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

З.Ы. Попробуй длинный комментарий к процедуре ИзмененияКлючейТЗ() сделать в несколько строк, а то он у меня на экран не помещается - неудобно читать статью. :-(
26. Shaman100M 1191 17.01.08 14:49 Сейчас в теме
(25) насчет (6) ( и (10) ) да, подсознательно фильтровал универсальные, но для полной картины включу. Можно, в принципе и его сделать универсальным, вынеся операции сравнения и присваивания в функции.
По комментарию - разве он у тебя не переносится на след. строки? Хотя, при копировании в конфигуратор лучше, чтобы строки были короткие.
27. poppy 3353 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 3353 18.01.08 16:52 Сейчас в теме
(28)
Да, действительно, решение (10) правильное. Я невнимательно его прочтала. Приношу извинения перед автором за напрасный поклеп. ;)
30. maloi_a 24.01.08 09:49 Сейчас в теме
(23)
Внесу свою копейку.
В Функции ПроверитьСтрокуТаблицы(ТЗ, СписокКлючей)
надо добавить объявление локальных переменных НомСтр и М1.
Перем НомСтр и М1;
Иначе может поменять глобальные переменные с такими именами.
31. poppy 3353 24.01.08 09:59 Сейчас в теме
(30) Правильное замечание.

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

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

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

Код
ТЗ.ВыбратьСтроки();
Пока ТЗ.ПолучитьСтроку() = 1 Цикл 
   Если ПроверитьСтрокуТаблицы(ТЗ, ТЗ.НомерСтроки - 1, СписокКлючей) = 1 Тогда
      // БЛОК 1 Создать новый документ
      // БЛОК 2 Заполнить заголовок документа
   КонецЕсли;
   
   // БЛОК 5 Заполнение строки спецификации документа
   
   Если ПроверитьСтрокуТаблицы(ТЗ, ТЗ.НомерСтроки, СписокКлючей) = 1 Тогда
      // БЛОК 3 Заполнить подвал документа
      // БЛОК 4 Записать / вывести документ
   КонецЕсли;
КонецЦикла;
Показать полностью
34. Shaman100M 1191 26.01.08 18:09 Сейчас в теме
35. Shaman100M 1191 16.03.09 19:41 Сейчас в теме
Оставьте свое сообщение

См. также

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

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

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

02.09.2019    1846    mkalimulin    140       

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

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

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

26.08.2019    4440    kirovsbis    28       

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

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

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

08.07.2019    4867    grumagargler    7       

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

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

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

07.07.2019    18503    olegtymko    197       

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

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

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

25.04.2019    6054    m-rv    2       

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

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

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

16.04.2019    8682    m-rv    16       

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

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

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

01.04.2019    17010    YPermitin    59       

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

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

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

17.03.2019    3278    dmarenin    0       

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

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

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

09.03.2019    10897    YPermitin    38       

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

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

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

06.03.2019    8238    Scorpion4eg    35       

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

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

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

29.01.2019    3610    scientes    15       

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

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

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

25.01.2019    3325    vasilev2015    0       

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

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

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

19.01.2019    3703    vasilev2015    0       

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

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

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

17.01.2019    4144    vasilev2015    50       

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

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

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

18.12.2018    4877    milkers    19       

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

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

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

29.11.2018    7774    dmarenin    9       

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

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

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

10.11.2018    22261    ids79    40       

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

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

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

17.10.2018    14484    pashamak    62       

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

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

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

15.10.2018    21521    tormozit    100       

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

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

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

31.07.2018    9608    1c-intelligence    59       

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

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

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

10.07.2018    16233    Артано    92       

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

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

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

02.07.2018    16686    Tavalik    12       

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

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

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

25.06.2018    20223    olegtymko    47       

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

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

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

01.06.2018    22145    m-rv    21       

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

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

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

24.05.2018    11088    Артано    36       

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

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

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

23.05.2018    17929    slozhenikin_com    19       

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

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

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

13.05.2018    12040    Rustig    9       

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

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

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

09.05.2018    10636    dsdred    28       

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

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

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

22.04.2018    12507    Evil Beaver    27       

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

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

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

03.03.2018    6461    Gladkov_Anton    9       

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

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

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

19.02.2018    37115    ildarovich    44       

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

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

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

12.02.2018    26091    Evil Beaver    97       

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

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

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

15.12.2017    13252    bforce    22