Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

To ToList() or not to ToList()?

Given an in memory (not LINQ to SQL) list of classes:

List<MyClass> myItems = /*lots and lots of items*/;

which I am grouping using a GroupBy() statement:

myItems.GroupBy(g => g.Ref)

and then immediately consuming in a foreach loop is there any difference in calling .ToList() on the "group" or should I just use an IEnumerable.

So full code examples:

With ToList()

List<List<MyClass>> groupedItemsA = new List<List<MyClass>>();
List<List<MyClass>> groupedItemsB = new List<List<MyClass>>();

List<MyClass> myItems = /*lots and lots of items*/;
List<IGrouping<string, MyClass>> groupedItems = myItems.GroupBy(g => g.Ref).ToList();
foreach(IGrouping<string, MyClass> item in groupedItems)
{
  if (/*check something*/)
  {
     groupedItemsA.Add(item.ToList());
  }
  else
  {
    groupedItemsB.Add(item.ToList());
  }
}

or

Using IEnumerable

List<List<MyClass>> groupedItemsA = new List<List<MyClass>>();
List<List<MyClass>> groupedItemsB = new List<List<MyClass>>();


List<MyClass> myItems = /*lots and lots of items*/;
IEnumerable<IGrouping<string, MyClass>> groupedItems = myItems.GroupBy(g => g.Ref);
foreach(IGrouping<string, MyClass> item in groupedItems)
{
  if (/*check something*/)
  {
     groupedItemsA.Add(item.ToList());
  }
  else
  {
    groupedItemsB.Add(item.ToList());
  }
}

Is there any difference in the execution plan of these "under the hood"? Would either of these be more efficient or does it not really matter?

I am not using the groupedItems list after this.

like image 920
Liam Avatar asked May 01 '15 10:05

Liam


3 Answers

Yes there is a difference and it can be significant.

ToList() will iterate and append each iterated item into a new list. This has the effect of creating a temporary list which consumes memory.

Sometimes you might want to take the memory penalty especially if you intend on iterating the list multiple times and the original list is not in memory.

In your particular example using the ToList() you actually end up iterating twice - once to build the list and a second time in your foreach. Depending on the size of the list and your application this may or may not be a concern.

like image 175
jaket Avatar answered Oct 30 '22 04:10

jaket


If you are sure you'll use groupedItems only once, then using .ToList() has a single advantage: if there is an exception (for example because your code is doing funny things for calculating .Ref) during the grouping, the exception will be in the .ToList() row instead of being inside the foreach... I don't think it is a big advantage (and perhaps it is a disadvantage).

To clarify:

public class MyClass
{
    public string Ref
    {
        get
        {
            // sometimes I like to throw an exception!
            if (DateTime.Now.Ticks % 10 == 0) throw new Exception();

            return "Foo";
        }
    }
}

Note that you have explicitly tagged this question as IEnumerable, and in your example myItems is a List<>, so I won't discuss of the difference of doing ToList() or not when you are reading data from a database through Entity Framework/Linq to SQL.

like image 29
xanatos Avatar answered Oct 30 '22 06:10

xanatos


Is there any difference?

Yes, .ToList() creates a new list from iterating the grouped collection:

The ToList<TSource>(IEnumerable<TSource>) method forces immediate query evaluation and returns a List that contains the query results.

Whether this is noticeable should be benchmarked by you.

If you only iterate the grouped collection once, the .ToList() step is unnecessary and will be relatively slower than directly enumerating the GroupBy() result.

like image 1
CodeCaster Avatar answered Oct 30 '22 05:10

CodeCaster