Using a list as input for function of a list of elements. (Python)

I’m having an issue using a list of values as an input for a function applied to a list of elements of equal length.

I have a list of elements and a list of values. Both lists are the same length and will always be the same length. I am trying to run SetPartCustomData methods (functions?) on that list of elements using the list of values as the custom data being set. So element one gets value 1 and so on.

I can’t figure out how to get the list of values into the function correctly so that the first value goes to the first element etc. Attached is my latest attempt, but it is trying to use all the values in the list instead of the one that corresponds to each element.

I think I need to use for i in list or something like that, but I don’t know how to write that correctly.

Edit: for clarity my inputs are…

Inpt = list of elements I am trying to run the function on
Cnt = the count of that list
idno = an integer that corresponds to a fabrication part custom data field (part of the method)
NewVal = The list of values I am trying to use in the function

If they will always be of the same length, you can use a zip function to iterate them easily.

def do_something(a, b):
    return a + str(b)

elements = ['a', 'b', 'c', 'd']
values = [1, 2, 3, 4]
output = []

for e, v in zip(elements, values):
    output.append(do_something(e, v))

OUT = output

you can do like this
for i, e in enumerate(Inpt):
e.SetPartCustomDataReal(idno, Newval[i])
…etc

The i value is the index of Inpt list which runs from 0 to the end. Then you use that index to pick the corresponding value from Newval List by using Newval[i]

Ok. I can’t get this suggestion to work. I think I’m implementing it right but I keep getting an "unexpected token " error when bringing it back into Revit. I mixed something up somewhere I think.

I took out 2 of the functions so that I’m only working on SetCustomDataText just to keep things simpler until I can learn how iterating/zipping works correctly. What am I doing wrong here?

import clr
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import FabricationPart
from Autodesk.Revit.DB import FabricationDimensionDefinition
from Autodesk.Revit.DB import FabricationDimensionUnitType

clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)

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

Inpt = UnwrapElement(IN[0])
Cnt = UnwrapElement(IN[1])
idno = (IN[2])
NewVal = (IN[3])
CustDType = list()


## zip to map elements to new values
mapped = zip(Inpt, NewVal)

def Setthevalue(a, b):
	a.SetPartCustomDataText(idno,b)

Doc = DocumentManager.Instance.CurrentDBDocument
TransactionManager.Instance.EnsureInTransaction(Doc)

if Cnt > 1:
	for e, v in zip(Inpt, NewVal)
		e.SetPartCustomDataText(idno,v)
else:
	Inpt.SetPartCustomDataText(idno,NewVal)
	CustDType.append(Inpt.GetPartCustomDataText(idno))

TransactionManager.Instance.TransactionTaskDone()

OUT = CustDType

You’re missing a colon after for e, vin zip(Inpt, NewVal):

Ok… That aside…

The code runs through dynamo now but it is applying the full list of values to each element still instead of applying each one once. So now the values going into the function is the full list. Here’s a snip if that makes it more clear. I’m expecting 0 to go to list 0, 1 to list 1, etc.

image

Wait don’t tell me. I think I got it. Hang on.

Yes. It is working as intended.

Short answer: I was misunderstanding the way that custom data is written to fabrication parts.

Long answer for anybody who stumbles on this later: There is functionally no difference between the three methods for setting custom data of fabrication parts. SetCustomDataText, SetCustomDataValue, and SetCustomDataInteger, all write to the exact same data field for the ITM. The only difference between them is the type of data that is being written (text, double, or integer). What happens when you enter the wrong kind of data is determined by how the custom data field was set up in the fabrication parts database. For example, the custom data field I was writing to will take any text string and convert it to a value or integer if it can, otherwise it will use a default of 0 for values and integers, even if it is a text field. Every custom data field has all 3 types of data, but will only display the one set when the field is created. What was confusing me is that I was using a number that was a string as the data I was trying to write, so it was coming through as all three data types because the custom data field was able to read the input as all three types. The list of lists above is not showing 4 values for each field. it is the integer value, the double value, and the text value of the SAME custom id field with each data type displayed in its own list. So. It’s all working as intended. Yay.

Here is my final script if anybody stumbles on it later. and needs to use it. Thanks for your help again @cgartland. That’s two I owe you.

import clr
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import FabricationPart
from Autodesk.Revit.DB import FabricationDimensionDefinition
from Autodesk.Revit.DB import FabricationDimensionUnitType

clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)

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

Inpt = UnwrapElement(IN[0])
Cnt = UnwrapElement(IN[1])
idno = (IN[2])
NewVal = (IN[3])
CustDType = list()


## zip to map elements to new values
mapped = zip(Inpt, NewVal)

def Setthevalue(a, b):
	a.SetPartCustomDataText(idno,b)

Doc = DocumentManager.Instance.CurrentDBDocument
TransactionManager.Instance.EnsureInTransaction(Doc)

if Cnt > 1:
	for a, b in mapped:
		Setthevalue(a,b)
else:
	Inpt.SetPartCustomDataText(idno,NewVal)
	CustDType.append(Inpt.GetPartCustomDataText(idno))

TransactionManager.Instance.TransactionTaskDone()

OUT = CustDType

Instead of making the function and create another zipped list. Why don’t you do it just like I suggested. It makes your code has fewer line and run faster.
import clr

clr.AddReference('RevitAPI')

import Autodesk

from Autodesk.Revit.DB import FabricationPart

from Autodesk.Revit.DB import FabricationDimensionDefinition

from Autodesk.Revit.DB import FabricationDimensionUnitType

clr.AddReference("RevitNodes")

import Revit

clr.ImportExtensions(Revit.Elements)

clr.AddReference("RevitServices")

import RevitServices

from RevitServices.Persistence import DocumentManager

from RevitServices.Transactions import TransactionManager

Inpt = UnwrapElement(IN[0])

Cnt = UnwrapElement(IN[1])

idno = (IN[2])

NewVal = (IN[3])

CustDType = list()

Doc = DocumentManager.Instance.CurrentDBDocument

TransactionManager.Instance.EnsureInTransaction(Doc)

if Cnt > 1:

  for i, each in enumerate(Inpt):

     a.SetPartCustomDataText(each,NewVal[i])

else:

   Inpt.SetPartCustomDataText(idno,NewVal)

   CustDType.append(Inpt.GetPartCustomDataText(idno))

TransactionManager.Instance.TransactionTaskDone()

OUT = CustDType

Doing it like that results in an error where the function is expecting a fabrication part element and it is getting a integer.

L-Vettz,

Would you be able to add a snippet of your graph so we can understand the application? That would be extremely helpful… lol

This has been marked as solved. I no longer need help.

I understand, I was requesting the graph to better understand how you were able to get this to work to be able to apply it myself.

Ohhhh ok.

Here is the custom node I built with it. It just takes a list of elements, the index of the custom data, and the custom data you want to write to as an input. I’m not really using this node for anything else yet. I’m still working on the front end part of the tool in building that will eventually use this node.

oh sorry. So if it’s about the data type, it more complicated than I thought.
By the way, it’s good to know that you have already solved your problem.