LINQ: using IEnumerable.Count () or IList.Count for better performance

Based on the following code:

var grouped = filters.GroupBy(p => p.PropertyName); int numOfRowElements = grouped.Count(); foreach (IGrouping<string, PropertyFilter> filter in grouped) { foreach (var propertyFilter in filter) { // do something } } 

where is the List filter, I understand that calling IEnumerable.Count () forces the request to execute. Is the result of this execution stored in a grouped variable, which is then used in the foreach loop, or is the foreach loop causing the request to execute again? Would it be better to do this instead?

  var grouped = filters.GroupBy(p => p.PropertyName).ToList(); int numOfRowElements = grouped.Count; foreach (IGrouping<string, PropertyFilter> filter in grouped) { foreach (var propertyFilter in filter) { // do something } } 

TIA.

+4
source share
1 answer

If the underlying data source is IList<T> , Enumerable.Count() will refer to the .Count property as an optimization, so there is no performance penalty. If this is not the case, then the listing will be forced. Consider this carefully.

 var someList = new List<int>(); var count = someList.Count(); // will use .Count property var count = someList.OrderBy(x => x).Count(); // will force enumeration 

In this example, I just get the list count in the second expression. In the third, I order a list, and then I get an invoice. Ordering a list returns a sequence, not a list. Therefore, the Count() method does not work with IList<T> , but IEnumerable<T> . In this case, the request must be transferred to obtain the result and will bear any cost that comes with it (in this case, the order).

In light of this, in the first fragment you list your request twice. Once, to get an account, once in the foreach. This will follow all the logic to group your data twice. The second example will perform grouping operations only once, but obviously iterate over the resulting list in foreach, which should be less expensive than repeating the grouping operation. (Regardless of whether you can measure the savings, it will completely depend on the size and / or data source in the source list. If in doubt, profile it.)


* There may be a small measured punishment for the layer of indirection, you will have to think it through if you think this is a true bottleneck. But think of the Count() method as

 if (sequence is IList<T>) { return ((IList<T>)sequence).Count } else { /* perform enumeration */; } 
+5
source

All Articles