How to sort a collection by type in LINQ

I have such a collection,

Class Base{} Class A : Base {} Class B : Base {} List<Base> collection = new List<Base>(); collection.Add(new A()); collection.Add(new B()); collection.Add(new A()); collection.Add(new A()); collection.Add(new B()); 

Now I want to sort the collection based on type (A / B). How can i do this? Please help me.

+6
c # linq
source share
8 answers

You can use the type information yourself:

 collection.Sort( (a,b) => { bool aType = a.GetType() == typeof(A); bool bType = b.GetType() == typeof(A); return aType.CompareTo(bType); }); 

This will work for the two types that you specified, but do not scale beyond. This allows you to explicitly specify the order (i.e. if you need elements "B" to "A", you can make it work using this technique).

If you need to support many types, and the order does not need to be specified in advance, you can do something like:

 collection.Sort( (a,b) => a.GetType().FullName.CompareTo(b.GetType().FullName) ); 

This will process any number of types (i.e.: C and subtype D, too) and arrange them by their full type.

+8
source share
 private static int OrderOnType(Base item) { if(item is A) return 0; if(item is B) return 1; return 2; } 

Then make a choice:

 collection.OrderBy(OrderOnType) 

or

 collection.Sort((x, y) => OrderOnType(x).CompareTo(OrderOnType(y))); 

Depending on whether you want to sort the place or not. You can put OrderOnType in a lambda if you want, but it seems to me more readable, and I prefer to store lambdas when they add, rather than reduce readability.

+6
source share
 collection.OrderBy(i => i.GetType() == typeof(A) ? 0 : 1); 

You will get a sequence with all A , then all B s

+4
source share

whether

 collection.Where(entry => entry is A).Concat(collection.Where(entry => entry is B)) 

do what you need?

+1
source share

This will be order, so A will be first and B second.

 var xx = list.OrderBy(x => x.GetType() == typeof(B)).ToList(); 

This following console project confirms:

 class Program { public class X { } public class A : X { } public class B : X { } static void Main() { List<X> list = new List<X>(); list.Add(new B()); list.Add(new A()); list.Add(new B()); list.Add(new A()); list.Add(new A()); // A.GetType() == typeof(B) will be "0" making the type A go first // B.GetType() == typeof(B) will be "1" making the type B go last var xx = list.OrderBy(x => x.GetType() == typeof(B)).ToList(); Console.ReadLine(); } } 

In this case, I assume that you have only A and B If you have more types, you will need to create a comparer to return a value for each type. You can also have a property in the base class that will set the order of elements, then you can sort the list with this property.

+1
source share

EDIT: I think this is what you want:

If you don't mind sorting β€œinappropriate” and reassigning the list, this should work:

 collection = collection.GroupBy(item => item.GetType()) .SelectMany(g => g) .ToList(); 

or depending on your needs, something like:

 collection = collection.OrderBy(item => item.GetType().FullName) .ToList(); 

If it should be in place, then probably the best choice would be to write a custom list.Sort and list.Sort .


To group items by type, you can use GroupBy :

 var groupedItems = collection.GroupBy(item => item.GetType()); 

This uses deferred execution.

Alternatively, you can put β€œgroups” in the data structure as follows:

 var itemsByTypeLookUp = collection.ToLookup(item => item.GetType()); foreach(A a in itemsByTypeLookUp[typeof(A)]) { ... } 

If you are looking for only a specific type:

 var itemsOfTypeA = collection.OfType<A>(); 
0
source share

Something like this works for me.

 collection.OrderBy(p => p.GetType().Equals(typeof(B))).ThenBy(p => p.GetType().Equals(typeof(A))).ToList(); 

My code is:

 class Employer; class Doctor : Employer class Administrator : Employer class Nurse : Employer List<Employer> collection = new List<Employer>(); collection.Add(new Doctor()); collection.Add(new Administrator()); collection.Add(new Doctor()); collection.Add(new Nurse()); collection.Add(new Administrator()); collection = collection.OrderBy(p => p.GetType().Equals(typeof(Nurse))).ThenBy(p => p.GetType().Equals(typeof(Doctor))).ThenBy(p => p.GetType().Equals(typeof(Administrator))).ToList(); 
0
source share

this is a later answer, but something simple that could work for others and worked during my testing to implement something like this

 var orderedList = animalList.OrderBy(x=> x.GetType().Name); foreach(var animal in orderedList) { System.Console.WriteLine(animal.Name); } 

the output will look like this:

 Ape Ape Ape Ape Cat Cat Cat Cat Cat Dog Dog Dog Dog Dog 

where animalList looks something like this:

 animalList = new List<IAnimal>(); 

and IAnimal interface / implementations:

 public class Ape : IAnimal { public string Name => "Ape"; public AnimalType AnimalType => AnimalType.Ape; } public class Dog : IAnimal { public string Name => "Dog"; public AnimalType AnimalType => AnimalType.Dog; } public class Cat : IAnimal { public string Name => "Cat"; public AnimalType AnimalType => AnimalType.Cat; } public interface IAnimal { string Name {get;} AnimalType AnimalType {get;} } 

furthermore, something like specifying an enum type that represents your class order may help. Example:

 public enum MyOrderType { Ape = 1, Cat = 2, Dog = 3 } 

then it's as simple as

 var orderedList = animalList.OrderBy(x=> x.AnimalType).ToList(); 
0
source share

All Articles