Reputation: 29760
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:
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
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.
Upvotes: 8
Views: 6970
Reputation: 19
If you were to use the IEnumerable
rather than the List()
each time you enumerate it, the GroupBy
expression would be re-evaluated against your myItems
List.
This means if you add another item to myItems
then enumerate it, that item will be included in the GroupBy
expression.
When you call ToList
however you create a new List and any changes to myItems
will not be included in groupedItems
.
Upvotes: 0
Reputation: 9341
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.
Upvotes: 9
Reputation: 111940
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.
Upvotes: 2
Reputation: 151730
Is there any difference?
Yes, .ToList()
creates a new list from iterating the grouped collection:
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.
Upvotes: 1