Loops Vs Non Loops / Formatting

Hello Everyone,

So I am new to programming and still trying to wrap my head around loops vs non loops. How to make them vs not make them. I have the following code that accepts 1 Document but want to get used to formatting them in a fashion that I can understand when a Loop is needed (For multiple) vs just accepting 1. Thank you for any help or guidance!

import clr

clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *

clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

doc = DocumentManager.Instance.CurrentDBDocument
uidoc=DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument

#Preparing input from dynamo to revit
linkDoc = UnwrapElement(IN[0])

#Do some action in a Transaction
TransactionManager.Instance.EnsureInTransaction(doc)

LinkSheets = FilteredElementCollector(linkDoc).OfCategory(BuiltInCategory.OST_Sheets).ToElements()

sheetRevs = []
revName = []
for sheet in LinkSheets:
	revs = sheet.GetAllRevisionIds()
	for r in revs:
		rev = linkDoc.GetElement(r)
		sheetRevs.Add(rev)
		revName.Add(rev.Name)
	

TransactionManager.Instance.TransactionTaskDone()

OUT = sheetRevs,revName

P.S. Feel free to use this if you are trying to get revisions from a linked file!

There are a few options. Many users tend to structure their nodes in a way that always treats their inputs as a list. For example:

docs = IN[0]
if not isinstance(docs, list):
    docs = [docs]

This way, a for loop can be used regardless of whether there is a single input or a list:

docs = IN[0]
if not isinstance(docs, list):
    docs = [docs]
for doc in docs:
    # do something

This will behave the same way given either type of input:

IN[0] = Document
# docs = [Document]
IN[0] = [Document, Document, Document]
# docs = [Document, Document, Document]

In your case, I don’t think a transaction is necessary as you are not modifying a document, so this can be omitted.

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

# Preparing input from dynamo to revit
link_docs = IN[0]
if not isinstance(link_docs, list):
    link_docs = [link_docs]

sheet_revs = []
rev_names = []
for link_doc in link_docs:
    sheets = FilteredElementCollector(link_doc).OfCategory(BuiltInCategory.OST_Sheets)
    for sheet in sheets:
	    revs = sheet.GetAllRevisionIds()
	    for r in revs:
	        rev = link_doc.GetElement(r)
            sheet_revs.append(rev)
            rev_names.append(rev.Name)

OUT = sheet_revs, rev_names

As you add more and more levels of nesting to your loops, it may be preferable to create a function to increase the modularity and legibility of your code:

def get_revisions(doc):
    """Given Document doc returns all its revisions and their names"""
    sheet_revs = []
    rev_names = []
    sheets = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Sheets)
    for sheet in sheets:
        rev_ids = sheet.GetAllRevisionIds()
        for id in rev_ids:
            rev = doc.GetElement(id)
            sheet_revs.append(rev)
            rev_names.append(rev.Name)
    return sheet_revs, rev_names

You could then use this function on each of your documents:

output = []
for doc in docs:
    output.append(get_revisions(doc))
OUT = output
3 Likes

O m G, this is so helpful! Thank you so much and can’t wait to mess with my own codes to differentiate between single and multiple items.

1 Like

Here is a prime example.

parameters = IN[0]
paramgroup = IN[1]
inst_or_typ = IN[2]
families = UnwrapElement(IN[3])

# class for overwriting loaded families in the project
class FamOpt1(IFamilyLoadOptions):
def __init__(self): pass
def OnFamilyFound(self,familyInUse, overwriteParameterValues): return True
def OnSharedFamilyFound(self,familyInUse, source, overwriteParameterValues): return True

trans1 = TransactionManager.Instance
trans1.ForceCloseTransaction() #just to make sure everything is closed down
# Dynamo's transaction handling is pretty poor for
# multiple documents, so we'll need to force close
# every single transaction we open
result = []

for f1 in families:

famdoc = doc.EditFamily(f1)

trans1.EnsureInTransaction(famdoc)
for p in parameters:
famdoc.FamilyManager.AddParameter(p, paramgroup, inst_or_typ)
trans1.ForceCloseTransaction()
famdoc.LoadFamily(doc, FamOpt1())
result.append(True)

So this should really be:

parameters = IN[0]
paramgroup = IN[1]
if not isinstance(paramgroup, list):
       paramgroup = [paramgroup]
inst_or_typ = IN[2]
families = UnwrapElement(IN[3])

# class for overwriting loaded families in the project
class FamOpt1(IFamilyLoadOptions):
def __init__(self): pass
def OnFamilyFound(self,familyInUse, overwriteParameterValues): return True
def OnSharedFamilyFound(self,familyInUse, source, overwriteParameterValues): return True

trans1 = TransactionManager.Instance
trans1.ForceCloseTransaction() #just to make sure everything is closed down
# Dynamo's transaction handling is pretty poor for
# multiple documents, so we'll need to force close
# every single transaction we open
result = []

for f1 in families:

famdoc = doc.EditFamily(f1)

trans1.EnsureInTransaction(famdoc)
for p in parameters:
famdoc.FamilyManager.AddParameter(p, paramgroup, inst_or_typ)
trans1.ForceCloseTransaction()
famdoc.LoadFamily(doc, FamOpt1())
result.append(True)