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

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

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

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

 

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

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

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

4 Comments

  1. Diversus

    В вашем случае рекурсией не проще?

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

    Показать

    Запуск пебора:

    ПереборВсехСтрокДереваЗначений(текДЗ)
    Reply
  2. harmer

    Рекурсия? Не, не слышал.

    PS http://infostart.ru/public/20797/

    Процедура ИзменитьПометкиПодчиненных(пГлавный)
    Подчиненные = пГлавный.Строки;
    Для Каждого Подчиненный Из Подчиненные Цикл
    Подчиненный.Пометка = пГлавный.Пометка;
    ИзменитьПометкиПодчиненных(Подчиненный);
    КонецЦикла;
    КонецПроцедуры
    Reply
  3. kosmo0

    (1)(2)

    Как вариант если влезаете в существующий большой код.

    Как необходимость если дерево значений в процессе обработки меняет состав узлов.

    Reply
  4. json

    Можно еще вот так перебрать все строки:

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

    Показать

    Пример в прищепке

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *