Secret ingredients to quality software

SSW Foursquare

Do you avoid iterating multiple times?

Last updated by Bryden Oliver on 22 Dec 2021 05:30 am (5 months ago) See History

Due to LINQ expressions being lazy executed, it is a important to avoid re-evaluating the expression. For LINQ extension methods, this is critically important.

There are 2 problems with multiple evaluations:

  • It is needlessly expensive
  • It may not be possible

Some IEnumerables may be tied to something like a Stream that doesn't support seeking. In this case, the enumeration can only occur once. This is true of the web request Content stream. That would mean that you simply can't enumerate it again as to start the enumeration again would require seeking back to the start.

public IEnumerable<Product> UpdateStockLevels(IEnumerable<Product> products)
{
    if (products.Any())
    {
        ... IfAnyItemsExist()
    }

    foreach (var product in products)
    {
        ... OnEachItem()
    }
}

Figure: Bad example - Calls any which enumerates the first item and then foreach which forces a second evaluation

public IEnumerable<Product> UpdateStockLevels(IEnumerable<Product> products)
{
    var first = true;    
    foreach (var product in products)
    {
        if (first)
        {
            ... IfAnyItemsExist()
        }
        ... OnEachItem()
        first = false;
    }
}

Figure: Good example - Only enumerates once

The worst part about this is that you may test it against an array, or some other input and it may seem fine. This is especially true with unit testing, as typically an incoming stream of objects is simulated by just providing a fixed array or list, but these will support re enumeration where the real input in your application may not.

Bryden OliverBryden Oliver

We open source. Powered by GitHub