Dynamo: фильтрация элементов в скрипте

18 July 2020

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

Теперь задачу чуть усложним: будем копировать имена не у всех труб, а только у труб определённой системы. Для этого нам и нужно изучить фильтрацию, а заодно и булеву математику. Не бойтесь, ничего сложного.

Уровень сложности: чуть выше дна.

Время создания: максимум 10 минут.

Версия Ревита и Динамо: 2020.2 и 2.3.0 (работать будет в любой версии).

Алгоритм

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

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

Скрипт

Итак, вот мой старый скрипт, оставлю от него первую часть, в которой получаю имена систем с труб. Они видны в ноде GetParameter.

Взял категорию «Трубы», все элементы в этой категории и получил значения параметра «Имя системы» у каждой трубы
Взял категорию «Трубы», все элементы в этой категории и получил значения параметра «Имя системы» у каждой трубы

Теперь я хочу отделить из списка элементов только те трубы, у которых имя системы равняется «Т21 1». Пример у нас простой, поэтому в модели есть только одна труба с таким именем системы. Это неважно, потому что будь их сто одна, скрипт был бы точно такой же.

Ноды

Чтобы добавить фильтрацию, нужен нод FilterByBoolMask — Отфильтровать по булевой маске. Булева маска — это список из булевых выражений true и false (тру и фолс). То есть истина/ложь или да/нет.

Маской они называются потому, что этот список из тру/фолс накладывается на список, который нужно отфильтровать. Как маска на лицо.

Вот наш нод в библиотеке. Достаточно просто набрать «filter»
Вот наш нод в библиотеке. Достаточно просто набрать «filter»
А вот так нод выглядит в рабочем пространстве
А вот так нод выглядит в рабочем пространстве

Если вся эта ерунда с маской пока понятна не до конца, то скоро мы проведём фильтрацию, и станет яснее.

На ноде FilterByBoolMask у нас два входа и два выхода.
List — это список, который мы будем фильтровать, в нашем случае — список с трубами.
Mask — это список-маска, его нужно создать.
Про выходы расскажу чуть позже.

Кроме нода с фильтром нам нужны Код Блок и нод «равно». Код Блок создаю двойным кликом по рабочему пространству, а «равно» возьму в библиотеке, просто напишу «=» в строке поиска и добавлю нод.

Сам нод называется «==», это не ошибка, так и должно быть
Сам нод называется «==», это не ошибка, так и должно быть

В программировании «==» означает проверку равенства двух переменных, а просто «=» означает присвоение значения переменной. То есть выражение a = b значит «записать в переменную a значение переменной b. Если a = 2, b = 3, то результатом a = b будет a равно 3. Грубо говоря, через одинарное «=» мы говорим, чему должна быть равна переменная.

Выражение a == b значит «сравнивать значения переменных a и b, если они равны, то выдать true (истина, действительно равны), если не равны, то выдать false (ложь, значения не равны). Таким образом в программировании сравниваются все величины и результат сравнения — это булевы выражения, либо да, либо нет, true или false.

Создание маски

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

Ноды для получения маски
Ноды для получения маски

То есть я беру нод для поверки равенства, на один вход подаю список с именами систем всех труб, а на второй вход подаю имя той системы, чьи трубы хочу обработать скриптом. В примере это труба с именем системы «Т21 1», этот текст и ввожу в Код Блок.

Если теперь я запущу скрипт, то на выходе из нода «==» получу список булевых выражений:

Вот так выглядит список с тру/фолс для маски
Вот так выглядит список с тру/фолс для маски

Посмотрите: скрипт прошёлся по каждому значению в списке с именами систем, сравнил значение с тем, что я задал как эталон, и выдал мне список тру/фолс. Если значение в списке совпало, то выдал тру. Если нет, то фолс. Так как у меня только одна труба с именем системы «Т21 1», то в списке у меня только один тру.

Заметьте, что у списков есть своя нумерация, но начинается она с нуля. Эти номера называют индексами. У меня в списке имён систем значение «Т21 1» расположено в индексе 0. И значение тру также расположено в индексе 0. Это важное соответствие индексов, так как следующим шагом мы будем накладывать эту маску на другой список.

Фильтрация

У нас есть список труб, есть маска. Логично, что из списка труб нам нужно оставить только те, у которых имя системы равно заданному (Т 21 1), то есть в маске стоит значение тру. Для этого нужно подать на нод фильтрации список труб и маску.

Схема фильтрации
Схема фильтрации

Важно! Мы подаём на нод фильтрации не список с именами систем, а список труб. Список с именами систем мы получили, чтобы создать маску через сравнение имён систем с заданным именем (Т21 1).

Что сейчас у нас есть. Есть список из 6 труб. Есть список из имён систем этих труб. Если маска. И вот эту маску я накладываю на список с трубами.

Далее я получаю два списка с элементами на выходах из нода фильтрации. В первом списке «in» у меня элементы, которые получили маску тру. Во втором списке «out» — элементы с маской фолс.

Можно не раскрывать список под нодом, а воспользоваться нодом Watch
Можно не раскрывать список под нодом, а воспользоваться нодом Watch

То есть на in я получаю те элементы, который удовлетворяют моим критериям фильтра (имя системы равно «Т21 1»), а на out всё то, что не прошло по критериям. Для этого и нужна маска.

Посмотрите на скриншот выше, элемент в списке, у которого индекс совпадает с индексом тру в маске, уходит в in, остальное — в out.

Если я заменю в Код Блоке имя системы с Т21 1 на Т11 1, то на выходах у меня будут уже другие трубы, так как критерии поменялись. Чтобы заметить разницу, посмотрите на айдишники элементов (зелёные блоки с числами).

Поменял имя системы для сравнения, маска поменялась, элементы на выходах нода фильтрации тоже сменились в соответствии с маской
Поменял имя системы для сравнения, маска поменялась, элементы на выходах нода фильтрации тоже сменились в соответствии с маской

Запись значений

Теперь я получил трубы, имя системы которых удовлетворяет моему равенству. Значит, нужно обрабатывать именно эти трубы (в примере это всего одна труба), а всё остальное мне не нужно.

Чтобы сделать это, я возьму элементы с выхода нода фильтрации «in», получу их имена системы и запишу в параметр комментарии.

Записываю значение в трубу
Записываю значение в трубу

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

Можете создать спецификацию в проекте и проверить, что получилось. Гарантирую, что всё сработает. При условии, что вы всё правильно сделали, конечно.

Выводы

  • Для фильтрации нам нужен список-маска из значений тру/фолс. Этот список мы как бы накладываем на изначальный список объектов.
  • На выходах фильтра мы получаем два списка, в in — те элементы, которые прошли со значением тру, в out — те, что с фолс. Все эти элементы можно и дальше обрабатывать скриптом, всё зависит от задачи.

Визуализировать фильтрацию по маске можно так: представьте, что у вас есть бумажка со списком из 10 позиции и такой же бумажный список-маска к нему. При этом в списке-маске вместо значений true будут прямоугольные прорези. Теперь, если наложить список-маску на исходный список, в прорезях увидим те позиции, которым соответствует true, а скроются те, у которых false. И вот то, что видно, отправится на выход in, а что скрыто — на out.

Другие примеры фильтрации

Отфильтровываю трубы, у которых длина больше 2500 мм
Отфильтровываю трубы, у которых длина больше 2500 мм
Отфильтровываю трубы с классификацией системы «Обратная жидкость» через нод «не равно (!=)»
Отфильтровываю трубы с классификацией системы «Обратная жидкость» через нод «не равно (!=)»

Всё. Если что-то осталось непонятно, пишите комментарии или задавайте вопросы в Телеграм-чате. Все ссылочки есть ниже.

Чтобы прокачать Ревит-навыки и не пропускать статьи в блоге, подпишитесь на мой Телеграм-канал «Блог Муратова про Revit MEP». Приглашайте коллег и знакомых проектировщиков. Можно обсудить статью и задать вопросы в специальном чате канала.

Отблагодарить автора

Я много времени уделяю блогу. Если хотите отблагодарить меня, то можете сделать небольшой подарок (именно подарок, такой перевод не облагается налогом).

Скачать скрипт из примера можно с Яндекс.Диска.