gifts2017

Обход группировок по иерархии

Опубликовал Павел Островский (32ops) в раздел Программирование - Практика программирования

Вроде и тема небольшая, не для статьи, но поиски в интернете показали, что найти ответ довольно сложно. Из-за простоты вопроса специалисты обычно отмахиваются, считая, что вопрошающий не разбирается с азами программирования, не понимает рекурсии. В итоге на форумах тема обычно остается без ответа, либо приводится только часть ответа кратко. На самом деле есть «подводные камни»,  которые нужно знать.

«Подводные камни», мешающие реализовать обход иерархии:

1)      В запросе в итогах нужно использовать ключевое слово ИЕРАРХИЯ, например, «ИТОГИ ПО Номенклатура Иерархия»

2)      При использовании Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией) ,если есть несколько уровней группировки, нужно указывать второй параметр, строку с именем поля группировки. Например, для иерархической группироки по номенклатуре правильно будет Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией, «Номенклатура»)

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

Сам алгоритм обхода.

1)      Без иерархии

Выборка1 = Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам); 
Пока Выборка1.Следующий() Цикл
  // Вставить обработку выборки Выборка1
  Выборка2 = Выборка1.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
  Пока Выборка2.Следующий() Цикл
    // Вставить обработку выборки Выборка2
    ОбработатьЭлемент();
  КонецЦикла;
КонецЦикла;

2)      Иерархия на первом уровне группировки, второй уровень без иерархии

           

ВыборкаСИерархией = Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией,"Номенклатура");
ВыбратьЭлементыВИерархии(ВыборкаСИерархией);
 
Процедура ВыбратьЭлементыВИерархии(ВыборкаСИерархией)
  Пока ВыборкаСИерархией.Следующий() Цикл
    Если ВыборкаСИерархией.ТипЗаписи()=ТипЗаписиЗапроса.ИтогПоИерархии Тогда
      ВыбратьЭлементыВИерархии (ВыборкаСИерархией.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией,"Номенклатура"));
    ИначеЕсли ВыборкаСИерархией.ТипЗаписи()=ТипЗаписиЗапроса.ИтогПоГруппировке Тогда
      ВыбратьЭлементыБезИерархии (ВыборкаСИерархией.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам));
    КонецЕсли;   
  КонецЦикла;
КонецПроцедуры
 
Процедура ВыбратьЭлементыБезИерархии (ВыборкаБезИерархии)
  Пока ВыборкаБезИерархии.Следующий() Цикл
    // Вставить обработку выборки ВыборкаБезИерархии
    ОбработатьЭлемент();
  КонецЦикла;
КонецПроцедуры

 

3) Первый уровень без иерархии, второй с иерархией

ВыборкаБезИерахии = Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);       
Пока ВыборкаБезИерахии.Следующий() Цикл
  // Вставить обработку выборки ВыборкаБезИерахии
  ВыборкаСИерархией = ВыборкаБезИерахии.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией,"Номенклатура"));
  ВыбратьЭлементыВИерархии(ВыборкаСИерархией);
КонецЦикла;
 
Процедура ВыбратьЭлементыВИерархии(ВыборкаСИерархией)
  Пока ВыборкаСИерархией.Следующий() Цикл
    Если ВыборкаСИерархией.ТипЗаписи()=ТипЗаписиЗапроса.ИтогПоИерархии Тогда
      ВыбратьЭлементыВИерархии (ВыборкаСИерархией.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией,"Номенклатура"));
    ИначеЕсли ВыборкаСИерархией.ТипЗаписи()=ТипЗаписиЗапроса. ДетальнаяЗапись Тогда
      ОбработатьЭлемент();
    КонецЕсли;   
  КонецЦикла;
КонецПроцедуры

4) Первый уровень без иерархии, второй с иерархией (без рекурсии)

    ВыборкаНоменклатура = Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией,"Номенклатура");
    
    Стек = Новый Массив ( 200 );
    КоличествоВСтеке=0;
    Выход=Не ВыборкаНоменклатура.Следующий();
    
    Пока Не Выход Цикл
        Пока ВыборкаНоменклатура.ТипЗаписи()=ТипЗаписиЗапроса.ИтогПоИерархии Цикл
            Стек[КоличествоВСтеке]=ВыборкаНоменклатура;
            КоличествоВСтеке=КоличествоВСтеке+1;
            // Обработка папки
            Сообщить(ВыборкаНоменклатура.Номенклатура);
            ВыборкаНоменклатура=ВыборкаНоменклатура.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией,"Номенклатура");
            ВыборкаНоменклатура.Следующий();
        КонецЦикла;
        // Обработка элемента
        Сообщить(ВыборкаНоменклатура.Номенклатура);
        // Обработка следующей группировки
        ВыбратьДанные(ВыборкаНоменклатура.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам));
        ЕстьСледующий= ВыборкаНоменклатура.Следующий();
        Пока Не ЕстьСледующий И КоличествоВСтеке>0 Цикл
            КоличествоВСтеке=КоличествоВСтеке-1;
            ВыборкаНоменклатура=Стек[КоличествоВСтеке];
            ЕстьСледующий= ВыборкаНоменклатура.Следующий();
        КонецЦикла;
        Если Не ЕстьСледующий И КоличествоВСтеке=0 Тогда
            Выход=Истина;
        КонецЕсли;
    КонецЦикла;



См. также

Подписаться Добавить вознаграждение

Комментарии

1. Андрей Кайгородов (mszsuz) 31.03.15 11:01
Рекурсия требует доп.расходов ресурсов и не удобна из-за того, что выходим из области видимости остальных переменных - приходится или параметрами их передавать или объявлять в теле модуля. Любую выборку можно обойти в одной процедуре и без рекурсий.
2. Павел Островский (32ops) 31.03.15 11:10
(1) Согласен. Но в данной статье не рассматривается преобразование рекурсии в циклический алгоритм, т.к. это отдельная тема. Хотя, в принципе, можно добавить нерекурсивный алгоритм в качестве примера.
3. Василий Майдан (dick steel) 31.03.15 11:28
Гуд. Но почему нету примера, когда в методе "Выбрать" указывается 3 параметра?
Автор, допиши статью, указав пример с использованием 3-ех параметров (подсказка - хороший пример при работе с датами). Сделай из своей статьи конфетку ;-)
4. борян петров (TODD22) 31.03.15 13:22
При использовании Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией) обязательно указание второго параметра, строки с именем поля группировки.

Второй параметр вроде как не обязательный. И если у нас нет других полей группировки то можно и не указывать второй параметр.
5. Яков Коган (Yashazz) 31.03.15 14:45
Всем советую ознакомиться с публикациями пользователя Ildarovich. Тогда вам откроется истина.
6. Shurik Shurik (Shurik1C) 31.03.15 16:35
У меня сейчас есть подобная задача, построить отчет в виде пирамиды сверху вниз, и я вот никак не могу его побороть(((
Уже кажется что в 1С эта задача не реализуема(((
Прикрепленные файлы:
7. Павел Островский (32ops) 31.03.15 17:15
(6) Дак выгрузи в дерево, чем не пирамида))
8. Павел Островский (32ops) 01.04.15 11:27
(1) Вот пример без рекурсии
	ВыборкаНоменклатура = Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией,"Номенклатура");
	
	Стек = Новый Массив ( 200 );
	КоличествоВСтеке=0;
	Выход=Не ВыборкаНоменклатура.Следующий();
	
	Пока Не Выход Цикл
		Пока ВыборкаНоменклатура.ТипЗаписи()=ТипЗаписиЗапроса.ИтогПоИерархии Цикл
			Стек[КоличествоВСтеке]=ВыборкаНоменклатура;
			КоличествоВСтеке=КоличествоВСтеке+1;
			// Обработка папки
			Сообщить(ВыборкаНоменклатура.Номенклатура);
			ВыборкаНоменклатура=ВыборкаНоменклатура.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией,"Номенклатура");
			ВыборкаНоменклатура.Следующий();
		КонецЦикла;
		// Обработка элемента
		Сообщить(ВыборкаНоменклатура.Номенклатура);
		// Обработка следующей группировки
		ВыбратьДанные(ВыборкаНоменклатура.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам));
		ЕстьСледующий= ВыборкаНоменклатура.Следующий();
		Пока Не ЕстьСледующий И КоличествоВСтеке>0 Цикл
			КоличествоВСтеке=КоличествоВСтеке-1;
			ВыборкаНоменклатура=Стек[КоличествоВСтеке];
			ЕстьСледующий= ВыборкаНоменклатура.Следующий();
		КонецЦикла;
		Если Не ЕстьСледующий И КоличествоВСтеке=0 Тогда
			Выход=Истина;
		КонецЕсли;
	КонецЦикла;
...Показать Скрыть
Alien_job; Shurik1C; +2 Ответить 1
9. Павел Островский (32ops) 01.04.15 13:51
10. Павел Островский (32ops) 01.04.15 13:54
(3) Честно говоря не понял, как это к статье относится
11. Игорь Дайнеко (Dnki) 23.07.15 21:28
Материал почитал с удовольствием. Часто простые вещи не пишутся простым языком.
Спасибо.
12. Shurik Shurik (Shurik1C) 05.01.16 18:54
(9) 32ops,

Спасибо! Решил проблему:)
13. Игорь Пашутин (Alien_job) 07.04.16 09:42
Спасибо. Раньше не сталкивался с обходом по иерархии а камней подводных оказывается навалом!
14. Игорь Пашутин (Alien_job) 07.04.16 09:54
(8) 32ops, Я правильно понял, что в примере без рекурсии "ВыбратьДанные" имеется ввиду обработать подчиненные группировки?
15. Павел Островский (32ops) 07.04.16 09:56
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа