The Dynamo visual programming add-in for Revit enables advanced information gathering, rapid model changes, and repetitive task automation previously not available with the out of the box tools. Working with robust Building Information Models often requires surgical list management -- the act of gathering, filtering, re-structuring, sorting, or otherwise altering clusters of data or information. Of all possible list management operations, the ability to target and isolate information is essential. In my experiences using Dynamo I have encountered many methods for selecting and isolating model elements, parameters, and numeric values in Revit. The following are some of the most common approaches that I find myself using time and again.
As an introduction to selecting items from a list I will be using the English alphabet (26 characters) as my dataset and I am searching for the letter D. Below are descriptions for four of the most common selection nodes. Notice how the output of each use a "true" or "false" value. This is called a boolean operation -- a computer science term for anything that results an either of only two outcomes (binary): true/false, yes/no, 1/0, black/white, etc.
- Contains - this node produces a true/false result to whether the list contains any occurence of the letter D (plugged into the "element" input port). Although the outcome is true meaning yes the list contains the letter D, this will limit us from being able to isolate this letter in later operations.
- List.ContainsItem - similar to the Contains node, this node also searches the entire list for the letter D. However by changing the lacing to Longest -- right click the symbol in the lower corner (see red square), go to Lacing, and click "Longest" -- the letter D is checked against every item in the alphabet and the only true value returned is at Index 3 where D resides. The downside of this approach is that a sublist is created for every item in the alphabet meaning that we would need to flatten the list -- collapse everything back into one list of true/false values -- before continuing on to further operations.
- String.Contains - this node is excellent for searching through lines of text for a particular word or select group of words. In this case since the alphabet list only contains a single letter at every index, this node can be used to find the letter D. However, if the list contained the names of fruit and we searched for the letter "a", the node would return true values for any word containing an "a" such as banana, apple, pear, etc. For this reason, using the node to search for singular items can be problematic.
- == (match) - the double equals sign is a symbol that comes from computer science where a singular equals sign indicates a math calculation therefore two equals signs means that something is "the same". This is my favorite node to use for selection operations because it will find matches for any input type whether a string, number, piece of geometry, or Revit element.
After using the contains/match nodes above to determine true/false values, the output can then be paired with the List.FilterByBoolMask node to split the outcome into two separate lists. In this case, using the == node generates a true value at Index 3 and false for all the rest. This list of true/false values is plugged into the List.FilterByBoolMask node as a mask to filter the original alphabet letters. The outcome is the letter D isolated into its own list.
SELECTING MULTIPLE ITEMS:
Oftentimes when working with a BIM model, you are looking to match multiple values at once. Building on the list management principles above, you can easily search the alphabet list for more than one letter. Inputing more than one letter into the == node requires that you switch the lacing to "Cross Product" (see small red square) because you are attempting to match multiple items against a list of multiple items, meaning that you need to pair all possible combinations. The result is a list of 3 true/false values for each letter in the alphabet since the == node is attempting to match the letters F, R, and X for each. Since we are checking for any match of those three letters, using the combination of List.Map and the List.AnyTrue node from the Clockwork package will comb through each list and identify whether any matches occur. The last step is to feed the new list of true/false values into the List.FilterByBoolMask node and the letters F, R, and X are separated from the rest of the alphabet.
I recently discovered a second approach to isolating a list of search items. Using the NullAllIndecesOf node from the SpringNodes package combs through a list and returns the Index number of any matching items. This can then be used in concert with the List.GetItemAtIndex node to extract the values from the original list at the matching indeces. This node works especially well if the list being searched has repeat instances of the values you are searching for. Also notice how there is no more need for the use of boolean (true/false) values as an intermediary step.
ADVANCED SELECTION - REVIT ELEMENTS:
The above list management principles can be applied to isolating and extracting elements from Revit. For example if you want to gather a list of all the chair families placed in a Revit model:
- The combination of Furniture in the Categories node and All Elements of Category will generate a list of all furniture families.
- Since we only want chairs, grouping the model elements by their family name will create organized sublists.
- The grouped sublists can then be searched for the word "Chair".
- Since the model elements are grouped in multiples of the same family, the combination of List.Map and the List.AnyTrue node from the Clockwork Package will check every sublist to see if any of the items contain a true boolean value for the text "Chair" in the family name. Another method for doing the same thing would be to use List.Map in concert with List.FirstItem, which would extract only the first true/false value from every sublist.
- The last step is to use List.FilterByBoolMask to filter out only the grouped sublists of Revit model elements that contain a boolean value of true.
One advantage of understanding list management principles is that tasks can be achieved from multiple approaches. Here is another variation of the above method for collecting all chairs in the model:
- Use the nodes Categories: Furniture and All Elements of Category to extract all of the furniture families.
- Get the name of each family and look for those that contain the word "Chair".
- Filter out all elements that did not yield a true value using the List.FilterByBoolMask node. As a means of verification you can insert some Count nodes to check how many families have been identified as chairs vs. other.
- Given that all of the model elements coming from the In output port of the List.FilterByBoolMask node, the final operation is to group all of the elements according to their family name. In theory this will get you the exact same results as the previous method.
There is an even easier way to select model elements, once again by using the NullAllIndecesOf node from the SpringNodes package:
- Collect all furniture families from the model.
- Use the NullAllIndecesOf node combined with the name of the families and the List.UniqueItems node to identify the individual indeces where matching items reside in the list and group them according to their shared family names.
- Feeding the sublists of indeces into List.GetItemAtIndex will extract the model elements from the original furniture list and group them accordingly.
- The last step would be to filter out only the chair family groups (not shown in the image).
Specific families or parameter values can be isolated using the == (match) node:
- Collect all furniture families from the model.
- Use the == node to compare a specific chair name against the list of family names to produce a list of corresponding true/false values.
- Filter out all of the Revit model elements that contain a true boolean value with List.FilterByBoolMask.
- Optional: apply a Count node to get the total number families placed in the model for that specific item.
Please keep in mind that these examples are only some of the methods for selecting and isolating items using list management and they may not necessarily be the best methods. Different tasks and model configurations will require different approaches but the more time spent practicing list management, the easier it will become to customize a solution for any problem.