How can I group my list by keys in python like the Dynamo List.GroupByKey node?
import clr #.NET Laden
import sys #sys is de fundamentele Python bibliotheek
#de standaard IronPython-bibliotheken
#sys.path.append('C:\Program Files (x86)\IronPython 2.7\Lib') #Imports the
#standaard IronPython-bibliotheken, die alles dekken, van servers en
#encryptie tot reguliere expressies.
import System #The System namespace in de hoofdmap .NET
from System import Array #.NET class voor het verwerken van array-informatie
import System.Collections.Generic as MGen #Module kan nu benaderd worden met MGen.xxxx
#from System.Collections.Generic import * #Hiermee kunt u generieke afhandelen. Revit's API
#soms wil hard-getypte 'generieke' lijsten, genaamd ILists. Als je niet nodig hebt
#deze kunt u deze regel verwijderen.
clr.AddReference('ProtoGeometry') #Een Dynamo-bibliotheek voor zijn proxygeometrie
#classes. Je hebt dit alleen nodig als je interactie hebt met geometrie.
import Autodesk.DesignScript.Geometry as AGeo #Module kan worden opgeroepen a=met AGeo.xxxx
#from Autodesk.DesignScript.Geometry import * #Laadt alles in Dynamo's
#geometriebibliotheek
clr.AddReference("RevitNodes") #Dynamo's nodes voor Revit
import Revit #Laad in de Revit-namespaces in RevitNodes
clr.ImportExtensions(Revit.Elements) #Meer laden van Dynamo's Revit-bibliotheken
clr.ImportExtensions(Revit.GeometryConversion) #Meer laden van Dynamo's
#Revit-bibliotheken. Je hebt dit alleen nodig als je interactie hebt met geometrie.
clr.AddReference("RevitServices") #Dynamo's classes voor het omgaan met Revit-documenten
import RevitServices
from RevitServices.Persistence import DocumentManager #Een interne Dynamo class
#dat het document bijhoudt waaraan Dynamo momenteel is gekoppeld
from RevitServices.Transactions import TransactionManager #Een Dynamo class voor
#transacties openen en sluiten om de database van het Revit-document te wijzigen
clr.AddReference("RevitAPI") #Verwijzing naar Revit's API DLL's toevoegen
clr.AddReference("RevitAPIUI") #Verwijzing naar Revit's APIUI DLL's toevoegen
import Autodesk #Loads the Autodesk namespace
import Autodesk.Revit.DB as RDB #Loading Revit's API UI classes module kan nu worden aangeroepen met RDB.xxxx
#from Autodesk.Revit.DB import * #Loading Revit's API UI classes
import Autodesk.Revit.UI as RUI # Loading Revit's API UI classes als RUI.xxxx
#from Autodesk.Revit.UI import * #Loading Revit's API UI classes
doc = DocumentManager.Instance.CurrentDBDocument #Dit is het actieve Revit document
uiapp = DocumentManager.Instance.CurrentUIApplication #Een handle instellen voor het actieve Revit UI-document
app = uiapp.Application #Een handle instellen op de momenteel geopende instantie van de Revit-toepassing
uidoc = uiapp.ActiveUIDocument #Een handle instellen op de momenteel geopende instantie van de Revit UI-toepassing
revit_version = int(doc.Application.VersionNumber)
# code omrekenen revit feet naar huidig ingestele document units
#einde code omrekenen revit feet naar huidig ingestele document units
#alle elementen van OST category ophalen
alleElementen = RDB.FilteredElementCollector(doc)
alleElementen.OfCategory(RDB.BuiltInCategory.OST_PipeCurves)
alleElementen.WhereElementIsNotElementType()
MyElem = alleElementen.ToElements()
SystemName=[] #lege lijst starten
for NE in MyElem:
Section=NE.get_Parameter(RDB.BuiltInParameter.RBS_SYSTEM_NAME_PARAM).AsString()
SystemName.append(Section)
gezipt = zip(MyElem, SystemName)
#wegschrijven naar uitvoer
OUT= gezipt
I want to group my pipes by the output of SystemName
This is my goto solution for python grouping, alternatively if you have itertools available its groupby() method works well if you turn your list into a dictionary.
I’m not entirely sure what’s going on in your specific python code, but this is an effective code to group things by keys:
def unique(items):
ulist=[]
for i in items:
if i not in ulist:
ulist.append(i)
return ulist
items = IN[0]
keys = IN[1]
ukeys = unique(keys)
#create empty output list
grplist = []
for i in range(len(ukeys)):
grplist.append([])
#find indices
inds = []
for key in keys:
inds.append(ukeys.index(key))
#fill output list
for item, ind in zip(items,inds):
grplist[ind].append(item)
OUT = grplist
I would absolutely not be surprised if there’s more elegant methods built into Python but this certainly works.
import clr
import sys
import System
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
import Autodesk.DesignScript.Geometry as DS
#import Revit API
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
import Autodesk.Revit.DB as DB
#import specify namespace
from Autodesk.Revit.DB.Plumbing import *
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
pipeSystems = DB.FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_PipingSystem).WhereElementIsNotElementType()
OUT = {p_sys.Name : [x for x in p_sys.PipingNetwork if isinstance(x, Pipe)] for p_sys in pipeSystems}
or with itertools.groupby mentioned by @GavinCrump
Little update, you can just define this GroupByKey function.
It gives you an output with both the grouped lists and the unique keys, just like the node.
def GroupByKey(Items,Keys):
UKeys=[]
for Key in Keys:
if Key not in UKeys:
UKeys.append(Key)
GrpList=[]
for empt in range(len(UKeys)):
GrpList.append([])
Inds=[]
for Key in Keys:
Inds.append(UKeys.index(Key))
for Item, Ind in zip(Items, Inds):
GrpList[Ind].append(Item)
return [GrpList,UKeys]
@PauLtus
How can I group inside a group?
Like levels in Dynamo?
def GroupByKey(Items,Keys):
UKeys=[]
for Key in Keys:
if Key not in UKeys:
UKeys.append(Key)
GrpList=[]
for empt in range(len(UKeys)):
GrpList.append([])
Inds=[]
for Key in Keys:
Inds.append(UKeys.index(Key))
for Item, Ind in zip(Items, Inds):
GrpList[Ind].append(Item)
return [GrpList,UKeys]
#einde code omrekenen revit feet naar huidig ingestele document units
cat_list = [RDB.BuiltInCategory.OST_PipeCurves, RDB.BuiltInCategory.OST_PipeFitting]
typed_list = MGen.List[RDB.BuiltInCategory](cat_list)
filter = RDB.ElementMulticategoryFilter(typed_list)
output = RDB.FilteredElementCollector(doc).WherePasses(filter).WhereElementIsNotElementType().ToElements()
#systemname ophalen
SystemName=[] #lege lijst starten
for NE in output:
SystemN=NE.get_Parameter(RDB.BuiltInParameter.RBS_SYSTEM_NAME_PARAM).AsString()
SystemName.append(SystemN)
#Group list
grplist = GroupByKey(output, SystemName)
#Grouped list 0 = elements 1 = keys
groups = grplist[0]
uniquekeys = grplist [1]
#check parameter in de groep
Section = []
for NE in groups:
try:
SectionN= NE.get_Parameter(RDB.BuiltInParameter.RBS_SECTION).AsValueString()
Section.append(SectionN)
except:
Section.append(None)
grplist_1 = GroupByKey(groups, Section)
OUT = Section
Something like that doesn’t exist in Python, you have to play around with for loops then.
When I started with Python I quite missed these levels, but doing it in Python is certainly more consistent.
It’s possible to use levels if you put this inside a custom node. You can then work across a data structure in a similar manner to a normal node, and apply lacing behaviour as well.
I want to group inside a grouped list, this is the grouped list:
The “section” return as a null:
import Autodesk #Loads the Autodesk namespace
import Autodesk.Revit.DB as RDB
def GroupByKey(Items,Keys):
UKeys=[]
for Key in Keys:
if Key not in UKeys:
UKeys.append(Key)
GrpList=[]
for empt in range(len(UKeys)):
GrpList.append([])
Inds=[]
for Key in Keys:
Inds.append(UKeys.index(Key))
for Item, Ind in zip(Items, Inds):
GrpList[Ind].append(Item)
return [GrpList]
def GetName(ele):
elename = None
try:
elename = ele.Name
except:
elename = RDB.Element.Name.__get__(ele)
return elename
#einde code omrekenen revit feet naar huidig ingestele document units
#categoriëen ophalen
cat_list = [RDB.BuiltInCategory.OST_PipeCurves, RDB.BuiltInCategory.OST_PipeFitting]
typed_list = MGen.List[RDB.BuiltInCategory](cat_list)
filter = RDB.ElementMulticategoryFilter(typed_list)
elementen = RDB.FilteredElementCollector(doc).WherePasses(filter).WhereElementIsNotElementType().ToElements()
#pipes en fittings ophalen
pipe_elem = []
for nw in elementen:
p_name = GetName(nw)
if p_name.Contains("Bochtstraal") or p_name.Contains("Alupex"):
pipe_elem.append(nw)
#elementen groeperen op systemname
systems = []
grplist = []
for np in pipe_elem:
system_name = np.get_Parameter(RDB.BuiltInParameter.RBS_SYSTEM_NAME_PARAM).AsString()
systems.append(system_name)
grplist = GroupByKey(pipe_elem, systems)
#buizen uit de groep halen
section = []
grp_elem_system = grplist [0]
for np in grp_elem_system:
try:
section_name = np.get_Parameter(RDB.BuiltInParameter.RBS_SECTION).AsString()
section.append(system_name)
except:
section.append(None)
OUT = section
You’ll need to take the logic one level deeper using a for loop I think. That or use a custom node with levels (if you want versatility that is my recommended approach).
def GroupByKey(Items,Keys):
UKeys=[]
for Key in Keys:
if Key not in UKeys:
UKeys.append(Key)
GrpList=[]
for empt in range(len(UKeys)):
GrpList.append([])
Inds=[]
for Key in Keys:
Inds.append(UKeys.index(Key))
for Item, Ind in zip(Items, Inds):
GrpList[Ind].append(Item)
return [GrpList,UKeys]
dataToGroup = IN[0]
keysForGroup = IN[1]
groupedData = []
for d,k in zip(dataToGroup,keysForGroup):
grouped = GroupByKey(d,k)
groupedData.append(grouped[0])
OUT = groupedData