RealWorldCoder
RealWorldCoder

Reputation: 1021

Linq not populating the other list

For some reason the 2nd list List2 isn't being populated, when it should.

        var List1 = new List<object1>();
        //populated List1 here

        var List2 = new List<object1>();

        List1.OrderByDescending(o => o.Cnt).Take(10).Select(s =>
        {
            List2.Add(s);
            return s;
        });

List2 should have 10 entries by now, but doesn't? How is it possible?

Upvotes: 1

Views: 71

Answers (4)

Alex
Alex

Reputation: 13224

This happens, because enumerables are lazily evaluated. The code in the Select will only be executed when you start iterating over the enumerable (i.e. consume it).

This allows you for instance to create enumerables that (potentially) return an infinite number of results, like in:

public static class MyInfiniteEnumerable
{
    public static IEnumerable<int> GetIt()
    {
        var x = 0;
        while (true)
            yield return x + 1;
    }
}

In your code, to start filling the List2 you will need to "consume" the IEnumerable by iterating over its elements until it is done. For instance like this:

var myEnum = List1.OrderByDescending(o => o.Cnt).Take(10).Select(s =>
{
    List2.Add(s);
    return s;
});
foreach (var e in myEnum)
    ; // do nothing, just iterate.

More useful would be:

var list2 = List1.OrderByDescending(o => o.Cnt).Take(10).ToList();

Or

list2.AddRange(List1.OrderByDescending(o => o.Cnt).Take(10));

Upvotes: 2

DWright
DWright

Reputation: 9500

It's a lazy evaluation problem. You are not doing anything with the Select, so the adds are not happening. If you do this, it will work:

var resultList = List1.OrderByDescending(o => o.Cnt).Take(10).Select(s =>
{
    List2.Add(s);
    return s;
}).ToList();  //Now List2 has 10 items.

Upvotes: 2

Blorgbeard
Blorgbeard

Reputation: 103447

It's not working because LINQ expressions are lazily evaluated. That Select function is not actually executed until you iterate over it, which you never do.

If you add a .ToList(); to the end, you should see it working.

However, that is not the idiomatic way to do what you're trying to do. As a commenter suggested, something like this would be much better:

var List2 = List1.OrderByDescending(o => o.Cnt).Take(10).ToList();

Or to add the values to an already populated list,

List2.AddRange(List1.OrderByDescending(o => o.Cnt).Take(10));

Upvotes: 2

Orel Eraki
Orel Eraki

Reputation: 12196

It's because Linq static functions are using Lazy execution that means they only executes the code when they need to.

That means only when you use methods like Count(), ToList() etc' .NET will give you the result you desire and start execute the code you wanted.

You can achieve the result you want through appending .ToList() to the end of your .Select().

But a better solution will be using other means.

Upvotes: 2

Related Questions