Christoph
Christoph

Reputation: 27995

Multiple enumeration of IEnumerable

I know IEnumerable has been discussed several times here but I couldn't find the answer to my specific question so I'm bringing it up as a new question.

Consider the following piece of code:

    static void Main(string[] args)
    {

        List<string> testList = new List<string> {"Test", "Test1", "Test1"};
        IEnumerable<string> filtered = testList.Where(x => x == "Test1");

        DoSomeWork(filtered);
        DoSomeMoreWork(filtered);
    }

    public static void DoSomeWork(IEnumerable<string> items)
    {
        foreach (var item in items)
        {
            Console.WriteLine("do some work");
        }
    }

    public static void DoSomeMoreWork(IEnumerable<string> items)
    {
        foreach (var item in items)
        {
            Console.WriteLine("do some more work");
        }
    }

Am I right, that this causes not only the two items in "filtered" to iterate two times but actually the items in "testList"? So, considering that "testList" was a big list with 10000 items and "filtered" reduces it to 10 items, it would be more clever to make "filtered" a list (aka use var and just append ToList() at the end)

EDIT: That's the most embarrassing question I ever asked here. I knew it would be bad to iterate an IQueryable for example because this would result in fetching the data twice from the DB. However I wasn't exactly sure about in memory lists. I would delete the question if I could ;-)

Upvotes: 6

Views: 3531

Answers (4)

Wouter de Kort
Wouter de Kort

Reputation: 39898

The big list will be reiterated twice. To check that this really happens change your query to:

List<string> testList = new List<string> { "Test", "Test1", "Test1" };
IEnumerable<string> filtered = from t in testList
                               where t == "Test1"
                               select t;

If you then set a breakpoint on the 'where t == "Test1" part, you will see that the debugger hits this line for both the iterations.

Upvotes: 7

Pranay Rana
Pranay Rana

Reputation: 176896

List is ultimatly inherit from IEnumrable check this

public class List<T> : IList<T>, ICollection<T>, 
    IEnumerable<T>, IList, ICollection, IEnumerable

One more thing you can create list of IEnurable using the following constructor avaialble

public List(
    IEnumerable<T> collection
)

EDIT

The derivedi.e filtered list is get iterated twice by the both methods but append .ToList() method at the end .

IEnumerable<string> filtered = testList.Where(x => x == "Test1").ToList();

http://msdn.microsoft.com/en-us/library/fkbw11z0.aspx

Upvotes: 0

gideon
gideon

Reputation: 19465

it would be more clever to make "filtered" a list (aka use var and just append ToList() at the end)

Yes, especially in terms of Linq-To-Entities etc.

Returning an IEnumerable with linq allows for differed execution. When you do append ToList() to the end, your list is returned right there.

See http://blogs.msdn.com/b/charlie/archive/2007/12/09/deferred-execution.aspx

Upvotes: 0

xanatos
xanatos

Reputation: 111850

The big list will be reiterated twice. if you don't want it, you can "materialize" the restriction.

var filtered = testList.Where(x => x == "Test1").ToList();

And there are many answers that tell you this. You should have searched better :-)

Upvotes: 1

Related Questions