Очистить дерево значений 1с

Обновлено: 06.07.2024

Есть дерево значений, в ней есть колонка "Количество". Нужно удалить из этого дерева строки, у которых количество равно нулю.
Делаю так:

При выполнении этого кода очищается все дерево значений, хотя есть строки с ненулевым количеством. Подскажите, где я мог накосячить? PS Отладчиком пробовал пройти, но конфигуратор падает после 2-3 проходов по циклу.

(1) sCHTASS, нужно обходить последнюю группировку и из нее удалять. А так как вы это описали не мудрено, что вылетит в ошибку. Думаю это вы дерево просто разрушаете. Непонятно, почему все ветки удаляются (проще всего сразу глянуть, попадают ли корневые ветки в массив результатов поиска).
Но юзать исключения как часть алгоритма - моветон.
Я бы на рекурсию переписал. Там элементарно сделать, чтобы удаление само по себе начиналось с вложенных веток.
(8) Он контролируемо разрушает дерево. (11) Xershi, Какой индекс? "СтрокаДереваЗначений" - это ссылка, а не индекс. (10) herfis, Хотя о чём это я? На рекурсии можно гораздо оптимально сделать - чтобы если удаляется корневая, вниз уже не идти. (10) Пробовал с использованием рекурскии - очень медленно работает. (16) Ну так я же говорил, что через рекурсию очень долго работает. "но конфигуратор падает после 2-3 проходов по циклу." - это как понят. Комп не ыдерживает такую простую оталдку?
А по теме - вы удаляете строки из массива, где нулевые позиции, равзе нет? "но конфигуратор падает после 2-3 проходов по циклу." - это как понят.

Падает с ошибкой виндовой.

А по теме - вы удаляете строки из массива, где нулевые позиции, равзе нет?
Ну как бы из текста кода понятно, что нужно. Нужно убрать из дерева значений все строки с количеством, равным нулю. "Для Каждого СтрокаДерева Из МассивСтрокКУдалению Цикл"
тут скорей всего надо так
"Для Каждого СтрокаДерева Из ДеревоОстатков Цикл"

(6) Свалилось с ошибкой

Ошибка выполнения запроса
Ошибка при выполнении запроса POST к ресурсу /e1cib/logForm:
по причине:
server_addr=tcp://[xvap1c03]:2564 descr=Ошибка сетевого доступа к серверу
(Windows Sockets - 10054(0x00002746). Удаленный хост принудительно разорвал существующее подключение. ) line=1041 file=Src\DataExchangeTcpClientImpl.cpp

И не забывать про то что когда удаляете строку индекс тоже смешается, поэтому лучше делать обратный обход. МоёДрево.Строки - у вас удаляет все строки вашего дерева.

СтрокиДерева = ?(СтрокаДерева.Родитель = Неопределено,
ДеревоОстатков.Строки,
СтрокаДерева.Родитель.Строки); //вот здесь возвращает - ДеревоОстатков.Строки и удаляет все строки т.о.

(20) Это нужно, чтобы удалить "нулевую" строку верхнего уровня.
ЗЫ. А, ччерт.. Так-то как раз и нельзя делать. Выборка может сбиться. Щаз перепишу.

нет )))) туплю я с утра. Видать у вас неправильно построено дерево.

Вот код, он работает:

НА форме лежит ДеревоЗначений (МоёДрево), с двумя колонками "Колонка1, Колонка2"

(22) Дерево корректное. Код, как полагал, рабочий. На отдельных примерах срабатывает нормально. А вот сейчас задача от тестера пришла. Начал отладчиком ковырять и нашел вот такую штуку.

Во, вот так попробуй:

(24) Да пробывал я уже. Сколько еще раз повторять этот вариант меня не устраивает из-за скорости обработки. (26) sCHTASS, Либо у тебя дерево как в Яндексе, либо ты где-то протупил. Озвучь размер дерева. (27) Дерева состоит из 3-5 уровней вложенности. На последнем уровне может быть до 500-600 строк. На верхнем уровне около 20 строк. Нулевых строк 84 шт. (29) sCHTASS, И сколько выполняется по времени? Что замер говорит? Просто интересно, на чем именно тормозит в таком простом коде.
Неужели из-за накладных расходов на саму рекурсию? Деревце средненькое весьма.
Что касается сабжевого кода - ты проверил, попадают или нет корневые узлы в массив результатов?
Если нет - тогда такая неадекватная реакция у 1С значит на попытку удаления невалидной ссылки. Хотя упасть, по-идее, должно было раньше. Можно попробовать в начале попытки еще воткнуть обращение к СтрокаДерева.Количество. Может, на нем лучше упадет :) Хотя я лично всё равно попробовал бы выяснить причину тормозов и решить вопрос без исключений. (36) Удаление строк выполняется где-то 700 раз. С рекурсией выполняется код где-то 2-3 секунды, с отбором строк меньше секунды. (32) Не получится. Дерево изменяется неоднократно при исполнении кода, переделкой запроса тут не обойдешься.

А если в Попытка Исключение КонецПопытки добавить СообщитьОписаниеОшибки()?
Попытка
//вашкод
Исключение
СообщитьОписаниеОшибки()
КонецПопытки

Что скажет?
Или винда опять упадёт?

(30) Ругается на строку СтрокиДерева.Удалить(СтрокаДерева); мол индекс выходит за пределы.

(31) sCHTASS, об этом я и писал. Индекс сместился.

С деревом мало работал, но основа везде одинакова. Удалять нужно с конца.

(39) Xershi, В таблице значений синтаксис удаления тоже имеет два разных варианта. "Удалять нужно с конца" - это семерочная мантра и в восьмерке актуальна только при удалении по индексу.

(40) herfis, как тогда удалять значения без потери индексов при обходе коллекции?

Если это мантра 1с7, тогда не могли бы вы поведать, что в 1с8 изменилось?

(41) Xershi,
Если вопросы остались, могу разъяснить подробно. (61) herfis, мы походу уже разобрали этот случай, но если это что-то новое конечно было бы кстати! (62) Xershi, Откуда ж я знаю, что новое :)
Добавлю только, что на восьмерке я вообще почти перестал пользоваться удалением по индексам, т.к. по ссылкам гибче, хотя и избыточнее в простых случаях.
Чаще в обычном цикле "Для Каждого" запоминаю ссылки для удаления и потом их удаляю в отдельном цикле, как в (24).
Да, в простых случаях избыточно. Но предельно простые случаи у меня как-то редко стали встречаться. Зато код читабельнее и легче расширяемый при необходимости. Проход ведь может быть многофункциональный, а не только для удаления некоторых строк. И обратный порядок обхода в этом случае - явный костыль, который ясности и простоты в бизнес-код отнюдь не привносит (а где-то может быть и вообще неприемлем). это дерево, тут нет понятия "с конца", тут есть понятие "снизу".
рабочий код по удалению строк дерева значений в (38). развели дискуссию на 40 постов.

(42) spezc, ну я представляю каждую ветвь как таблицу значений.

Поэтому и с конца.

(45) Xershi, вам же уже сказали, что удаление происходит не по индексу, значит всё будет ОК. Вот вам пример:

См. вложение. Процедура отрабатывает корректно: сначала удаляет 2 строку со значением 2, потом удаляется 3 строка со значением 4 (хотя в момент попадания массива она была 4) и т.д. Всё корректно отработалось.
Хотите пример перепишите с ТЗ, с Деревом - всё-равно будет всё нормально пока вы удаляете не по индексу.

(47) klinval, так ты делаешь избыточную операцию! Лучше и быстрее один раз обойти с конца за один проход.

Никто не спорт что такое решение будет работать. Только ты 2 обхода делаешь.

Я же говорил про удаление за один обход. В таком ключе у вас есть решение/предложение?

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

(50) klinval, о том что твой пример для ТЗ, а у него ДЗ.

И метод которым он получил данные не гарантирует корректную сортировку.

Т.е. он удалил ветвь, а потом пытается удалить потомка, который уже удален.

(53) Xershi, тебе не стыдно мне повторять мою же мысль только другими словами?
(52) klinval 07.12.15 15:29
Изначально код возможно не работал из-за того, что удалялась строка уровнем выше, а потом идёт попытка удалить строку уровнем ниже, которой физически не существует.
Т.е. есть элементы 1, 1.1, 1.2, 2, 2.1 и т.д. Идёт удаление элемента 1, он тянет за собой 1.1 и 1.2. Потом пытаемся удалить 1.1, а этой строки уже нет. (53) Xershi 07.12.15 15:31
Т.е. он удалил ветвь, а потом пытается удалить потомка, который уже удален.

А теперь почему:

(50) klinval, о том что твой пример для ТЗ, а у него ДЗ. (39) Xershi, В таблице значений синтаксис удаления тоже имеет два разных варианта. "Удалять нужно с конца" - это семерочная мантра и в восьмерке актуальна только при удалении по индексу.

(40) herfis, как тогда удалять значения без потери индексов при обходе коллекции?

Если это мантра 1с7, тогда не могли бы вы поведать, что в 1с8 изменилось?

Объект «ДеревоЗначений» в 1С 8.3 представляет собой динамический набор значений любого типа. Для такого набора доступны свойства «колонки» и «строки» где каждая строка может иметь набор подчинённых строк, а каждая подчинённая строка набор своих подчинённых строк и т.д. Программная инициализация дерева значений в 1С осуществляется с помощью оператора НОВЫЙ.

ДеревоЗначений = Новый ДеревоЗначений;


Полезно понимать, что объект «ДеревоЗначений» схож с объектом «ТаблицаЗначений». Основной отличительный признак наличие дополнительного реквизита «Родитель» у объекта «ДеревоЗначений», с помощью которого и организовывается иерархия и подчинённость.

Дерево значений на управляемой форме

Если появляется необходимость показать данные в виде дерева пользователю, следует на форме создать реквизит с типом «ДеревоЗначений» и определится с составом колонок.


Для отображения на форме добавим реквизит в раздел элементов формы простым перетаскиванием.


Заполнение дерева значений

Получите понятные самоучители по 1С бесплатно:

Заполнить данными дерево значений в 1С можно программно (вручную) или получить из результата запроса. Рассмотрим на примерах оба способа.

Ручное заполнение реквизита формы с типом «ДеревоЗначений»

Результат запроса на форме:


Заполнение дерева значений из результата запроса

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

Результат запроса на форме может выглядеть так:


Поиск строк в дереве значений

Для поиска строк в дереве значений существует два способа, точнее говоря, метода.

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

Для примера найдём строку со значением «Элемент №1» в дереве значений вида:



Из результата видно, что метод вернул первую попавшуюся строку, и поиск был прекращён.

Если необходимо найти все строки со значением «Элемент №1» тогда следует использовать метод НайтиСтроки()

  • НайтиСтроки(<ПараметрыОтбора>, <ВключатьПодчиненные>)


Очистка дерева значений или строк

Для очистки дерева значений пригодятся методы Очистить(), Удалить(). Пример кода:

С помощью данных методов возможно удаление конкретных строк дерева значений.

. При удалении либо очистки строки все её подчинённые строки удалятся.

Обход дерева значений в 1С

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

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

Состав элементов и реквизитов формы:


Используя данный способ можно легко преобразовать таблицу значений обратно в дерево значений. Из примера «ГУИД» это уникальный идентификатор строки, а «Родитель» уникальный идентификатор родителя. Если обратного преобразования не требуется можно исключить использование колонок «Родитель» и «ГУИД».

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

Программное создание дерева значений

Как уже упоминалось выше, каждая строка имеет свойство Строки , которое содержит коллекцию дочерних строк. И сам объект ДеревоЗначений имеет свойство Строки , которое содержит коллекцию строк верхнего уровня.

  • Добавляет колонку в конец коллекции колонок дерева значений.
  • Возвращаемое значение: КолонкаДереваЗначений .

Заполнить табличное поле на форме

Визуальное представление дерева значений на форме обеспечивает элемент Таблица .



Пример программного заполнения дерева значений для управляемых форм:



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


Свернуть и развернуть строки дерева значений

Свернуть и развернуть дочерние строки элемента дерева значений можно с помощью методов Свернуть() и Развернуть() .

  • Сворачивает узел в указанной строке дерева.
  • ИдектификаторСтроки — идентификатор строки таблицы.
  • Разворачивает узел в указанной строке дерева.
  • ИдектификаторСтроки — идентификатор строки таблицы.
  • СПодчиненными — определяет необходимость раскрытия подчиненных узлов.
  • Получает коллекцию элементов дерева верхнего уровня.
  • Возвращаемое значение: ДанныеФормыКоллекцияЭлементовДерева .
  • Получает коллекцию дочерних элементов.
  • Возвращаемое значение: ДанныеФормыКоллекцияЭлементовДерева .

Для представления в форме объектов конфигурации (справочники, документы и т.п.) существуют специальные типы данных:

  • ДанныеФормыСтруктура — содержит набор свойств произвольного типа. Свойствами могут быть другие структуры, коллекции или структуры с коллекциями. Таким типом представляется, например, в форме СправочникОбъект .
  • ДанныеФормыКоллекция — это список типизированных значений, похожий на массив. Доступ к элементу коллекции осуществляется по индексу или по идентификатору. Доступ по идентификатору может отсутствовать в некоторых случаях. Это обусловлено типом прикладного объекта, который представлен этой коллекцией. Идентификатором может быть любое целое число. Таким типом представляется, например, в форме табличная часть.
  • ДанныеФормыСтруктураСКоллекцией — это объект, который представлен в виде структуры и коллекции одновременно. С ним можно обращаться как с любой из этих сущностей. Таким типом представляется, например, в форме набор записей.
  • ДанныеФормыДерево — объект предназначен для хранения иерархических данных.

Прикладной объект представлен либо одним, либо несколькими элементами данных формы. Например, документ, содержащий табличную часть, будет представлен объектом типа ДанныеФормыСтруктура (собственно документ), которому подчинен объект типа ДанныеФормыКоллекция (табличная часть документа).

Удалить строку и очистить дерево значений

Поиск в дереве значений

Среди наиболее часто используемых методов стоит отметить метод Найти() коллекции строк дерева значений.

  • Значение (обязательный, тип Произвольный ). Искомое значение.
  • Колонки (необязательный, тип Строка ). Список имен колонок, в которых будет осуществляться поиск, разделенных запятыми. Если параметр не указан, поиск осуществляется по всем колонкам дерева. Значение по умолчанию — Пустая строка.
  • ВключатьПодчиненные (необязательный, тип Булево ). Определяет, будут ли участвовать в поиске строки подчиненных коллекций (если таковые имеются). Если Истина — строки подчиненных коллекций участвуют в поиске. Значение по умолчанию — Ложь .

Метод осуществляет поиск значения в дереве в указанных колонках коллекции строк дерева значений. Возвращает строку (тип СтрокаДереваЗначений ), которая содержит искомое значение. Если значение не найдено, то возвращается значение Неопределено . Предназначен для поиска уникальных значений.

Строки и колонки имеют индексы, по которым к ним можно обращаться напрямую (начинаются с 0). Кроме этого, к колонкам можно обращаться по идентификатору.


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

Дерево значений является полностью динамическим объектом, т.е. Вы можете манипулировать не только строками дерева, добавляя и удаляя их, но и колонками.

Создание дерева значений

Как и большинство объектов встроенного языка, новая дерево значений может быть создано с помощью оператора Новый :

Свойства и методы дерева значений

Имя Тип Описание
Свойства
Колонки КоллекцияКолонокДереваЗначений содержит коллекцию колонок дерева значений
Строки КоллекцияСтрокДереваЗначений содержит коллекцию корневых строк дерева значений
Методы
ВыбратьСтроку() СтрокаДереваЗначений открывает диалог для интерактивного выбора строки дерева значений
Скопировать() ДеревоЗначений создает новый объект копированием текущего (копируются все колонки и строки)

Колонки дерева значений

Прежде чем начать работу с деревом значений, необходимо создать структуру колонок. Каждая колонка характеризуется следующими свойствами:

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

Доступ к колонкам производится через свойство Колонки объекта ДеревоЗначений . Для добавления новой колонки используется метод Колонки.Добавить():

Для того, чтобы определить наличие колонки с нужным именем используется метод Колонки.Найти():

Перебор колонок выполняется следующим образом:

Для удаления колонки используется метод Колонки.Удалить():

Методы коллекции колонок дерева значений

Вставить() Вставляет новую колонку в указанную позицию коллекции
Добавить() Добавляет новую колонку в конец коллекции
Индекс() Возвращает индекс колонки в коллекции колонок
Получить() Возвращает колонку по ее индексу
Количество() Возвращает количество колонок в коллекции
Найти() Ищет колонку в коллекции по имени
Очистить() Удаляет все колонки из коллекции
Сдвинуть() Сдвигает колонку влево или вправо
Удалить() Удаляет колонку из коллекции

Строки дерева значений

С колонками разобрались. Давайте теперь разберемся со строками. Строки дерева значений можно программно добавлять и удалять, перемещать и сортировать, а также выполнять операции поиска и отбора.

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

Имя Тип Описание
Свойства
Родитель СтрокаДереваЗначений ссылается на строку верхнего уровня. Для корневой строки имеет значение Неопределено
Строки КоллекцияСтрокДереваЗначений содержит коллекцию подчиненных строк
Методы
Владелец() ДеревоЗначений возвращает ссылку на дерево значений, которому принадлежит строка
Уровень() Число возвращает уровень вложенности строки в иерархии дерева. Для строки, не имеющей родителя, уровень будет равен 0 (верхний уровень или корневой уровень). Подчиненная ей строка будет иметь уровень 1 и т.д.

Добавление и удаление строк

Для добавления новой строки используется метод Строки.Добавить(). Метод возвращает объект СтрокаДереваЗначений , с которым доступны дальнейшие манипуляции:

И только теперь мы можем заполнить строку данными. Для этого обращаемся к ячейкам строки, указывая идентификаторы колонок через точку:

Для удаления строки используется метод Строки.Удалить(). Строку можно удалить передав методу либо саму строку, либо ее индекс:

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

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

Поиск строк

Поиск в дереве значений можно выполнять не только по значению в колонке (в этом случае будет возвращена первая найденная строка), но и по набору свойств (в этом случае возвращается массив строк).

Поиск возможен даже среди вложенных строк. Внимательно изучите документацию к методам Строки.Найти() и Строки.НайтиСтроки().

Все методы коллекции строк дерева значений:

Вставить() Вставляет строку на указанное место коллекции строк
ВыгрузитьКолонку() Выгружает значения ячеек указанной колонки из текущей коллекции строк в массив значений
Добавить() Добавляет новую строку в коллекцию строк
ЗагрузитьКолонку() Загружает значения из массива в ячейки указанной колонки коллекции строк
Индекс() Возвращает индекс строки дерева значений в коллекции
Итог() Возвращает просуммированный итог по колонке дерева значений
Количество() Возвращает количество строк в коллекции строк
Найти() Выполняет поиск строки по значению
НайтиСтроки() Выполняет поиск строк по указанным параметрам
Очистить() Удаляет все строки из текущей коллекции строк
Получить() Возвращает строку по ее индексу
Сдвинуть() Сдвигает строку вверх или вниз по коллекции строк
Сортировать() Выполняет сортировку строк в коллекции по указанным колонкам
Удалить() Удаляет строку из коллекции строк

Иерархию свойств и типов значений, связанных с деревом значений, схематически можно представить в виде дерева:

Читайте также: