Get all items from a ost_category list

Very good morning with everyone.
I’m learning Python so I’m very new.
My query is:
I’m trying to get items from an OST category list.
The first thing that occurred to me is to create a line of code for each of the categories and I have a fairly long code.
Help Is there a way to use a short code to return the elements of the category list… if it does not find an element in the category, it will return null?
I did a little research and I think it could be done with a function, but I don’t know how to create it, much less how to apply it within a list of categories.
I leave some images and files that I was trying to make.
Thank you very much for your support and time.


02_GET ELEMENTS OF LIST CATEGORY.dyn (21.8 KB)
LIST CATEGORY.xlsx (10.7 KB)

Instead of a line for each, build a list of the categories. Then iterate over that list to get the elements or the items.

The beauty of this is that it will return a nested list with an empty list where there is nothing, and a list with elements where there is something.

Not at the CPU, so this likely has some typos, but it should give you some direction.

categoriesList = [ ] #your categories go here
results = [] # list to hold the final output
for i in categoriesList: 
    elems = FilteredElementCollector(doc).OfCategory(i).WhereElementIsNotElementType().ToElements() # 
    if len(elems) == 0: elems= none #convert to null when empty list
    results.append(elems) #add to the results list
1 Like

Thanks for the support.
But now it happens that the list of categories that I have comes from an xlsx file. Therefore it is a text, not a category object.
HOW COULD I CONVERT A TEXT INTO A CATEGORY OBJECT?
Thank you.

If you are going to hard code it, don’t use text, but type out the full enumerator, ie: BuilInCategory.OST_Wall not just “OST_Wall”

1 Like

I understand what you mention… but the error is in having a list of categories that, by not placing “”, python understands that it is a variable but not a category…

Don’t utilize the string at any point. Just like you did in your first example…

That means I would have to do it line by line for each category…???

That is what hard coding means, yes.

What is it you are actually trying to do?

Out of my curiosity, here are some tests with different methods


  • with multi FilteredElementCollector call loop (CPython3 and Ipy engines)
    call FilteredElementCollector for each loop
import clr
import System
from System.Collections.Generic import List

clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import FilteredElementCollector, BuiltInCategory, ElementId

clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
doc = DocumentManager.Instance.CurrentDBDocument

cat_list = [System.Enum.Parse(BuiltInCategory, cat_value) for cat_value in IN[0]]
results = [] # list to hold the final output
for i in cat_list: 
    elems = FilteredElementCollector(doc).OfCategory(i).WhereElementIsNotElementType().ToElements() # 
    if len(elems) == 0: elems= None #convert to null when empty list
    results.append(elems) #add to the results list
OUT = results

  • with Numpy vectorization (CPython3 engine only)
    with 1 call of FilteredElementCollector with ElementMulticategoryFilter
    just for test, there may be improvements to be made

import clr
import System
from System.Collections.Generic import List

clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import FilteredElementCollector, BuiltInCategory, ElementId, ElementMulticategoryFilter

clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
doc = DocumentManager.Instance.CurrentDBDocument

import numpy as np

cat_list = [System.Enum.Parse(BuiltInCategory, cat_value) for cat_value in IN[0]]
typed_list = List[BuiltInCategory](cat_list)
filtercat = ElementMulticategoryFilter(typed_list)

arrayMultiCat = np.array(FilteredElementCollector(doc).WherePasses(filtercat).WhereElementIsNotElementType().ToElements())

groupList = [arrayMultiCat[np.vectorize(lambda x : x.Category.Id == ElementId(bic))(arrayMultiCat)] for bic in cat_list]
groupList = [grp if len(grp) > 0 else None for grp in groupList]

OUT = groupList

  • with the power of Linq (Ipy 2 or Ipy3 engines only)
    with 1 call of FilteredElementCollector with ElementMulticategoryFilter
import clr
import System
from System.Collections.Generic import List

clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import FilteredElementCollector, BuiltInCategory, ElementId, ElementMulticategoryFilter

clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
doc = DocumentManager.Instance.CurrentDBDocument

clr.AddReference("System.Core")
clr.ImportExtensions(System.Linq)

cat_list = [System.Enum.Parse(BuiltInCategory, cat_value) for cat_value in IN[0]]
cat_listId = [ElementId(c) for c in cat_list]
typed_list = List[BuiltInCategory](cat_list)
filtercat = ElementMulticategoryFilter(typed_list)

fecMultiCat = FilteredElementCollector(doc).WherePasses(filtercat).WhereElementIsNotElementType()
#                       
dict_group = fecMultiCat.OrderBy(lambda x : cat_listId.IndexOf(x.Category.Id))\
                        .GroupBy(lambda x : x.Category.Id)\
                        .ToDictionary(lambda g : g.Key, lambda g : g.ToList() )
# convert to python dict
pydict = dict(dict_group)
groupList2 = [pydict.get(cadId, None) for cadId in cat_listId]

OUT = groupList2

  • with itertools.groupby (CPython3 and Ipy engines)
    with 1 call of FilteredElementCollector with ElementMulticategoryFilter
import clr
import System
from System.Collections.Generic import List

clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import FilteredElementCollector, BuiltInCategory, ElementId, ElementMulticategoryFilter

clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
doc = DocumentManager.Instance.CurrentDBDocument

from itertools import groupby

cat_list = [System.Enum.Parse(BuiltInCategory, cat_value) for cat_value in IN[0]]
cat_listId = [ElementId(c) for c in cat_list]
typed_list = List[BuiltInCategory](cat_list)
filtercat = ElementMulticategoryFilter(typed_list)

fecMultiCat = FilteredElementCollector(doc).WherePasses(filtercat).WhereElementIsNotElementType().ToElements()
groupby_obj = groupby(sorted(fecMultiCat, key = lambda x : cat_listId.index(x.Category.Id)), key = lambda x : x.Category.Id)
dict_group = {key : list(group) for key, group in groupby_obj}
#
groupList2 = [dict_group.get(cadId, None) for cadId in cat_listId]

OUT = groupList2

Result with TuneUp

5 Likes

Thank you all very much, your comments and perspectives on what was raised have been very useful to me.

1 Like

Use the built in python function eval()

ListCategories = ["OST_Walls", "OST_Windows", "OST_Doors", "OST_Floors"]
ListCategories = [eval("BuiltInCategory." + cat) for cat in ListCategories]
2 Likes