gifts2017

Перебор всех строк дерева значений в глубину

Опубликовал Иван Иванов (kosmo0) в раздел Программирование - Универсальные функции

Процедура и функция перебора всех строк дерева значений в глубину.

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

Представленное на картинке дерево значений через процедуру обработает строки в следующем порядке - Строка1, Строка2, Строка3, Строка4, Строка5, Строка6, Строка7, Строка8.

 

Процедура ПереборВсехСтрокДереваЗначений()
    СтрокаДЗ=СледующаяСтрокаДЗ(НужноеДеревоЗначений);
    Пока СтрокаДЗ<>Неопределено Цикл
        //
        //обработка строки дерева значений
        //
        СтрокаДЗ=СледующаяСтрокаДЗ(НужноеДеревоЗначений, СтрокаДЗ);
    КонецЦикла;
КонецПроцедуры

// Выбор следущей строки дерева значений после переданной в качестве параметра строки.
//Следующей строкой считается первая из найденных - 1)первая подчиненная строка; 2)следующая строка на уровне
//с переданной строкой; 3)следующая строка на уровне родителя переданной строки; 4)если пункт 3 не привел
//к результату, то обрабатывается родитель родителя и далее вверх по иерархии дерева значений.
//Если переданная в качестве параметра строка является последней в дереве значений, то вернется Неопределено.
//
// Параметры:
//  текДЗ - ДеревоЗначений - днерево значений в котором осуществляется выбор следующей строки
//  текСтрокаДЗ - Неопределено - выбор первой строки корня дерева значений
//              - СтрокаДереваЗначений - строка дерева значений после котрой необходимо найти следующую строку
//
// Возвращаемое значение:
//  Неопределено - после переданной строки дерева значений отсутствуют строки или в дереве значений строки отсутствуют.
//  СтрокаДереваЗначений - следующая строка в дереве значений, расположенной после переданной строки дерева значений,
//                         либо первая строка корня дерева значений (если переданная строка дерева значений равна Неопределено)
//
Функция СледующаяСтрокаДЗ(текДЗ, текСтрокаДЗ=Неопределено)
    СтрокаВозв = Неопределено;
    Если текСтрокаДЗ=Неопределено Тогда //с самого начала дерева значений
        СтрокаВозв = ?(текДЗ.Строки.Количество()=0, Неопределено, текДЗ.Строки[0]);
    Иначе
        Если текСтрокаДЗ.Строки.Количество()<>0 Тогда  //есть подчиненные строки - заходим внутрь
            СтрокаВозв = текСтрокаДЗ.Строки[0];
        Иначе
            ОбрабатываемаяСтрокаДЗ = текСтрокаДЗ;
            Пока ОбрабатываемаяСтрокаДЗ<>Неопределено Цикл
                РодительОбрабСтрДЗ = ОбрабатываемаяСтрокаДЗ.Родитель;
                СтрокиНаУровнеОбрабСтрокиДЗ = ?(РодительОбрабСтрДЗ=Неопределено, текДЗ.Строки, РодительОбрабСтрДЗ.Строки);
                Если СтрокиНаУровнеОбрабСтрокиДЗ.Количество()>(СтрокиНаУровнеОбрабСтрокиДЗ.Индекс(ОбрабатываемаяСтрокаДЗ)+1) Тогда
                    СтрокаВозв = СтрокиНаУровнеОбрабСтрокиДЗ[СтрокиНаУровнеОбрабСтрокиДЗ.Индекс(ОбрабатываемаяСтрокаДЗ)+1];
                    Прервать;
                Иначе
                    ОбрабатываемаяСтрокаДЗ = РодительОбрабСтрДЗ;
                КонецЕсли;
            КонецЦикла;
        КонецЕсли;
    КонецЕсли;
    Возврат СтрокаВозв;
КонецФункции



ps. Уточню, что данный перебор не оптимален в подавляющем большинстве случаев. В подавляющем большинстве случаев стоит использовать рекурсию (найти примеры ее в сети не составляет труда).
В каких случаях следует присмотреться к использованию данного кода:
1. При необходимости влезть в большой кусок кода. То есть то, что раньше выполнялось один раз теперь необходимо выолнять со строками дерева значений. При этом кусок кода выполняемый в цикле затруднительно вынести в отдельную процедуру/функцию из-за значительного количества переменных, которые надо будет передавать в эту выделенную процедуру/функцию.
Но даже в этом варианте можно вызовом рекурсии получить все узлы дерева значений (и поместить их, например, в список значений или массив) и затем организовать цикл. Так проще и код лаконичнее.
2. Когда дерево значений в процессе обработки меняет состав узлов. Вот тогда и становится нужна функция СледующаяСтрокаДЗ().

См. также

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

Комментарии

1. Виталий Барилко (Diversus) 11.11.15 17:56
В вашем случае рекурсией не проще?

Процедура ПереборВсехСтрокДереваЗначений(текСтрока)
  СтрокиДЗ = текСтрока.Строки;
   Для Каждого ТекСтр Из СтрокиДЗ Цикл
       // Что-то делаем со строкой
       //...
      ПереборВсехСтрокДереваЗначений(ТекСтр);
   КонецЦикла;
КонецПроцедуры
...Показать Скрыть


Запуск пебора:
ПереборВсехСтрокДереваЗначений(текДЗ)
karpik666; hawkmax; surikateg; ya.Avoronov; bashinsky; ojiojiowka; BigB; +7 Ответить 2
2. Dmitry E (harmer) 11.11.15 18:00
Рекурсия? Не, не слышал.

PS http://infostart.ru/public/20797/
Процедура ИзменитьПометкиПодчиненных(пГлавный)
    Подчиненные = пГлавный.Строки;
    Для Каждого Подчиненный Из Подчиненные Цикл
        Подчиненный.Пометка = пГлавный.Пометка;
        ИзменитьПометкиПодчиненных(Подчиненный);
    КонецЦикла;
КонецПроцедуры
...Показать Скрыть
ya.Avoronov; BigB; +2 Ответить 1
3. Иван Иванов (kosmo0) 13.11.15 12:35
(1)(2)
Как вариант если влезаете в существующий большой код.
Как необходимость если дерево значений в процессе обработки меняет состав узлов.
4. Иван Иванов (kosmo0) 13.11.15 12:39
(1) Вы бы хоть код корректный писали. А то хегня, а не код. Как из корня запускается то?
5. Пишу код как картины (yurii_host) 14.09.16 05:50
Можно еще вот так перебрать все строки:

Функция ПолучитьВсеСтрокиДереваЗначений(Дерево) Экспорт
	ИмяВременнойКолонки = "_ВременнаяКолонка_";
	Дерево.Колонки.Добавить(ИмяВременнойКолонки);
	
	Отбор = Новый Структура(ИмяВременнойКолонки, Неопределено);
	ВсеСтрокиДерева = Дерево.Строки.НайтиСтроки(Отбор, Истина);
	
	Дерево.Колонки.Удалить(ИмяВременнойКолонки);
	
	Возврат ВсеСтрокиДерева;
КонецФункции
...Показать Скрыть


Пример в прищепке
Прикрепленные файлы:
ВнешняяОбработка1.epf
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа