C # split List of interfaces by implementation

I need to split List<IInterface> to get lists of specific IInterface implementations. How can I do this in an optimal way?

  public interface IPet { } public class Dog :IPet { } public class Cat : IPet { } public class Parrot : IPet { } public void Act() { var lst = new List<IPet>() {new Dog(),new Cat(),new Parrot()}; // I need to get three lists that hold each implementation // of IPet: List<Dog>, List<Cat>, List<Parrot> } 
+6
source share
5 answers

You can make GroupBy by type:

 var grouped = lst.GroupBy(i => i.GetType()).Select(g => g.ToList()).ToList() 

If you need a dictionary by type you can do:

 var grouped = lst.GroupBy(i => i.GetType()).ToDictionary(g => g.Key, g => g.ToList()); var dogList = grouped[typeof(Dog)]; 

Or as Tim suggested in a comment:

 var grouped = lst.ToLookup(i => i.GetType()); 
+11
source

You can use OfType :

 var dogs = lst.OfType<Dog>().ToList(); var cats = lst.OfType<Cat>().ToList(); var parrots = lst.OfType<Carrot>().ToList(); 
+4
source

There are answers so far. Their implementations all use linq and create many new lists and data gaps, here is a single-pass implementation that is more efficient, but not so beautiful. Below is the code comparing my approach with everyone else here:

print first:

Time spent using heinzbeinz: 6533

Time spent using Arturo Menchaki: 6450

Time spent using johnny 5: 5261

Time spent using Matt Clark (no linq): 2072

  Stopwatch sw = new Stopwatch(); sw.Start(); for (int k = 0; k < 1000000; k++) { // heinzbeinz var petLists = pets.GroupBy(i => i.GetType()).Select(g => g.ToList()).ToList(); } sw.Stop(); Console.WriteLine($"Time taken using heinzbeinz: {sw.ElapsedMilliseconds}"); sw.Reset(); sw.Start(); for (int k = 0; k < 1000000; k++) { // Arturo Menchaca var dogs = pets.OfType<Dog>().ToList(); var cats = pets.OfType<Cat>().ToList(); var parrots = pets.OfType<Parrot>().ToList(); } sw.Stop(); Console.WriteLine($"Time taken using Arturo Menchaca: {sw.ElapsedMilliseconds}"); sw.Reset(); sw.Start(); for (int k = 0; k < 1000000; k++) { // johnny 5 var dogs = pets.Where(x => x is Dog).ToList(); var cats = pets.Where(x => x is Cat).ToList(); var parrots = pets.Where(x => x is Parrot).ToList(); } sw.Stop(); Console.WriteLine($"Time taken using johnny 5: {sw.ElapsedMilliseconds}"); sw.Reset(); sw.Start(); for (int k = 0; k < 1000000; k++) { // Matt Clark var dogs = new List<Dog>(); var cats = new List<Cat>(); var parrot = new List<Parrot>(); foreach (var pet in pets) { if (pet is Dog) { dogs.Add(pet as Dog); } if (pet is Cat) { cats.Add(pet as Cat); } if (pet is Parrot) { parrot.Add(pet as Parrot); } } } sw.Stop(); Console.WriteLine($"Time taken using Matt Clark (no linq): {sw.ElapsedMilliseconds}"); 
+3
source

You can use linq only a filter of those of the type you are looking for. However, if you are trying to break things down into any lists of all Implementations that may be complex, and you will have to use reflection

 var dogs = lst.Where(x => x is Dog).ToList() var cats = lst.Where(x => x is Cat).ToList() var parrots = lst.Where(x => x is Parrot).ToList() 
+1
source

You can use better

 var dogs = lst.OfType<Dog>().ToList() var cats = lst.OfType<Cat>().ToList() var parrots = lst.OfType<Parrot>().ToList() 
0
source

All Articles