Search code examples
c#linqlistportable-class-library

How do I flatten a List<IList>()?


I have the following property:

public List<List<MyClass>> Items { get; set;}

This is bound to a ListViews ItemSource which is IEnumerable.

It is this IEnumerable ItemSource property that I am now trying to flatten.

I have managed to cast it to the following

this.ItemsSource.Cast<IList>().ToList();

because the following cast threw an "Invalid Cast Exception":

this.ItemsSource.Cast<List<object>>().ToList();

I am now looking to flatten this list to just a straight list of objects. I looked at this answer: Flatten List in LINQ and did:

this.ItemsSource.Cast<IList>().ToList().SelectMany(x => x);

But I get this error:

'List' does not contain a definition for 'SelectMany' and no extension method 'SelectMany' accepting a first argument of type 'List' could be found (are you missing a using directive or an assembly reference?)

So what am I doing wrong? Is it possible to flatten a List<IList>()?

Extra Information:

It may be worth mentioning that I am using Xamarin and this code is part of my PCL (portable class library) although I'm sure this wont be the reason.

While investigating what's going on here I have also tried:

List<string> s = new List<string>();
s.SelectMany(x => x);

and I get the error:

The type arguments for method 'Enumerable.SelectMany<TSource, TResult>(IEnumerable, Func<TSource, IEnumerable>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.


Solution

  • Try this:

    this.ItemsSource.Cast<IEnumerable>().SelectMany(sublist => sublist.Cast<object>()).ToList()
    

    I tested this with this sample program, and it compiled, and run:

    class Test
    {
        public List<List<int>> Items { get; set; }
    
        public IEnumerable ItemsSource { get { return this.Items; } }
    
        public List<object> Flatten
        {
            get { return this.ItemsSource.Cast<IEnumerable>().SelectMany(sublist => sublist.Cast<object>()).ToList(); }
        }
    }
    
    static class Program
    {
        static void Main()
        {
            var t = new Test();
            t.Items = new List<List<int>>
            {
                new List<int> { 1, 2 },
                new List<int> { 11, 12 }
            };
    
            var r = t.Flatten;
        }
    }
    

    I assumed that, even though you know the type of the items, you pretend not to know when using the flattened list... that is why it returns a list of objects instead of a list of ints.