List<Category> of physical element using LinQ and Categories list in VG

List<Category> of physical element using LinQ and Categories list in VG

Shai.Nguyen
Advocate Advocate
1,201 Views
4 Replies
Message 1 of 5

List<Category> of physical element using LinQ and Categories list in VG

Shai.Nguyen
Advocate
Advocate

It seems an old problem, but I find in forum for long time and didn't find solution.

Question 1:

My Idea is get a List<Category> of physical element. Here is my code

ICollection<Element> allElelements = new FilteredElementCollector(doc, doc.ActiveView.Id).WhereElementIsNotElementType()
                    .Where(x => (x.Category != null) && x.GetTypeId() != null)
                    .Where(x => x.IsPhysicalElement())
                    .ToList();
List<Category> catList = allElelements
                .Select(x => x.Category)
                .Distinct()
                .ToList();

But maybe Distinct is not working here so that the list has duplicate categories.

duplicate cat.PNG

How can I fix my code?

 

Question 2:

I want to get all category list of VG overrides in tab "Model Categories"

vg list.PNG

I use Category.CategoryType = CategoryType.Model but it contains some Categories that i don't want to.

catlist in vg.PNG

Thank you in advanced. Your solution is appriciated. 

0 Likes
Accepted solutions (1)
1,202 Views
4 Replies
Replies (4)
Message 2 of 5

Shai.Nguyen
Advocate
Advocate

Question 3:
How Can I sort a List<Category>?

I found a topic that: https://forums.autodesk.com/t5/revit-api-forum/find-all-categories-with-instances/m-p/7246344/highli...

It's seem be like what I want. but I don't know what class "CategoryNameComparer" is..

0 Likes
Message 3 of 5

RPTHOMAS108
Mentor
Mentor
Accepted solution

The Category class has a property CategoryType which returns an enum value such as Model, so you can filter by this. Before this was invented I used to filter by HasMaterialQuantities but I recently discovered in the UI some Model categories don't have a material quantity. Would have been nice to know the volume of a stair at one point.

 

This is more of a general .Net question than RevitAPI.

 

List(T).Distinct() will only work if the class implements IEquatable(of T), not sure if this has been done for the Category class. If it hasn't then you need to use the .Distinct overload that takes a class that implements IEqualityComparer(Of T).

 

Similarly to sort items the Category class would have to implement IComparable(Of T), it may exist however sorts by something other than name e.g. ID (not sure). Again you can use an overload for .Sort that takes a class that implements IComparer(of T).

 

This can be as simple as below since string has a default comparer:

 

public class Example
{
	public void SortCategories()
	{
		List<Category> C = new List<Category>();
		//Sort
		C.Sort(new MyCategoryComparerByName());
		//Unique
		C = C.Distinct(new MyCategoryEqualityComparer()).ToList;
	}
	private class MyCategoryComparerByName : IComparer<Category>
	{
		public int Compare(Category x, Category y)
		{
			return string.Compare(x.Name, y.Name);
		}
	}
	private class MyCategoryEqualityComparer : IEqualityComparer<Category>
	{

		public bool Equals(Category x, Category y)
		{
			return x.Id == y.Id;
		}

		public int GetHashCode(Category obj)
		{
			return obj.Id.IntegerValue;
		}
	}
}

 

Message 4 of 5

RPTHOMAS108
Mentor
Mentor

As a less verbose alternative to the about you can use Lambda expressions with the LINQ extensions but that may be harder to understand if you've first not considered how the basic interfaces mentioned above work.

0 Likes
Message 5 of 5

Shai.Nguyen
Advocate
Advocate

thank you Thomas. Your solution is what I've been looking for these day. It seems that there are a lot of thing I have to learn. 🙂

0 Likes