I'm creating a list of views that contain .dwg ImportInstance(s). For each view in the document, I'm using a FilteredElementCollector to get a list of elements meeting the criteria; if the list of elements meeting the criteria is not empty, then the view is added to the list:
foreach (Element viewElement in viewElements) { View view = (View)viewElement;
var stopwatch = new Stopwatch(); stopwatch.Start(); List<Element> elementsInView = new FilteredElementCollector(doc, view.Id).OfClass(typeof(ImportInstance)).Where(e => e.Category.Name.EndsWith(".dwg")).OfType<Element>().ToList(); stopwatch.Stop(); Debug.WriteLine(view.Name + ": " + stopwatch.ElapsedMilliseconds + "ms"); if(elementsInView.Count > 0) //if the current view contains at least 1 DWG ImportInstance, then the view is added to the list { viewsWithCAD.Add(view); continue; } }
The FilteredElementCollector can understandably take an upwards of 4000ms to collect elements from a view containing many elements. My goal is only to see if a single element exists in a view--not to collect all of the elements meeting the criteria; if I could make the FilteredElementCollector stop immediately after finding an element meeting the criteria, that would be helpful.
I would appreciate any advice on how to achieve this more efficiently.
Thank you.
Solved! Go to Solution.
Solved by FAIR59. Go to Solution.
Stopping the collector at the first element:
Element e = new FilteredElementCollector(doc, view.Id).OfClass(typeof(ImportInstance)).FirstElement();
Possible Speed improvement:
IEnumerable<ImportInstance> instances = new FilteredElementCollector(doc) .OfClass(typeof(ImportInstance)) .Cast<ImportInstance>(); List<ElementId> toExclude = new List<ElementId>(); foreach(ImportInstance instance in instances) { if ( !instance.Category.Name.EndsWith(".dwg")) { toExclude.Add(instance.Id); continue; } if( instance.ViewSpecific) // dwg only exists in ownerview { View ownerview = doc.GetElement(instance.OwnerViewId) as View; viewsWithCAD.Add(ownerview); if( viewElements.Contains(ownerview)) viewElements.Remove(ownerview); } } foreach (Element viewElement in viewElements) { View view = (View)viewElement; var stopwatch = new Stopwatch(); stopwatch.Start(); Element e = null; if (toExclude.Count>0) { e = new FilteredElementCollector(doc, view.Id) .Excluding(toExclude) .OfClass(typeof(ImportInstance)) .FirstElement(); } else{ e = new FilteredElementCollector(doc, view.Id) .OfClass(typeof(ImportInstance)) .FirstElement(); } stopwatch.Stop(); Debug.WriteLine(view.Name + ": " + stopwatch.ElapsedMilliseconds + "ms"); if(e!=null) //if the current view contains at least 1 DWG ImportInstance, then the view is added to the list { viewsWithCAD.Add(view); } }
Many thanks for the interesting question, and many thanks to Fair59 for yet another extremely knowledgeable and helpful solution!
I do keep pointing out that converting a filtered element collector to a List is an inefficient thing to do, if you can avoid it.
It forces the collector to retrieve all the data, convert it to the .NET memory space, duplicate it, costing time and space.
For the same reasons, it is much more efficient to test and apply as many filters as possible within the Revit memory space before passing any data across to .NET.
In this case, you can test the parameter values using a parameter filter instead of the LINQ post-processing that you are applying in you sample code snippet.
As Fair59 points out and we have discussed in the past, you can cancel a collector as soon as your target has been reached:
So, you can save time and space in several ways:
Use a parameter filter instead of LINQ post-processing
Do not convert to a List
Both of these force the filtered element collector to retrieve and return all results.
Here is an explanation of the various types of filters versus post-processing in .NET:
Here are some discussions and a benchmark of the results of using a parameter filter versus LINQ post-processing:
We also discussed the issue of finding all views displaying an element a couple of times in the past:
Cheers,
Jeremy
Can't find what you're looking for? Ask the community or share your knowledge.