开发者

Accessing Rows In A LINQ Result Without A Foreach Loop?

For every single LINQ query I've written, I've always used a foreach loop to go through the result. Now, I have a program where I want to get the first 50 rows of the result, do some calculations with 开发者_开发问答those rows, then get the next 50 rows of the result etc.

What is the good standards way to do this using LINQ and C#?


.Skip().Take() is going to be the best method (as far as clarity goes) in this case. For example:

var results = db.Table.Select(); // Your query here

int rowCount = results.Count(); // Count rows once and store

for(int i = 0; i <= rowCount; i += 50)
{
    var paged = results.Skip(i).Take(50);

    // do the calculations with the groups of 50 here
}

It is worth noting that even though this seems more clear (you're taking groups of 50 from the results), each time you call Skip() and Take() there's a chance that the collection has to be enumerated over again...which is actually less efficient than simply using foreach to enumerate over the results a single time.


You could use a group by ie:

data.Select((item, index) => new {item, index}).GroupBy(g => g.index / 50)

then you'd do your operation on each group.

similar to this: How to use Linq to group every N number of rows


Without knowing anything about the nature of the data and/or the calculations, the "good standards" way to do this would probably be a foreach loop!

It would help if you could provide some information about the nature of the data and the calculations that you want to perform. Depending on that, the best answer might be foreach, Skip/Take, GroupBy or maybe something else altogether.


Using .Skip(...).Take(...) will work for paging. But something to consider is that again an IEnumerable<...> this will recalculate the enumerable each time it is processed. Is this is something that is consumed instead of being resettable you could have issues. This method set can fix this problem.

public static class EnumerableEx
{
    public static IEnumerable<IEnumerable<T>> AsPages<T>(
        this IEnumerable<T> set, int pageLength)
    {
        using (var e = set.GetEnumerator())
            while (true)
                yield return GetPage(e, pageLength);
    }
    private static IEnumerable<T> GetPage<T>(
       IEnumerator<T> set, int pageLength)
    {
        for (var position = 0; 
            position < pageLength && set.MoveNext(); 
            position++)
            yield return set.Current;
    }
}

... Here is a usage example of why it is important.

class Program
{
    private static int _last = 0;
    private static IEnumerable<int> GetValues()
    {
        while (true)
            yield return _last++;
    }

    static void Main(string[] args)
    {
        for (var i = 0; i < 3; i++)
            foreach (var value in GetValues().Skip(5 * i).Take(5))
                Console.Write(value + ",");
        // 0,1,2,3,4,10,11,12,13,14,25,26,27,28,29,
        Console.WriteLine();
        _last = 0;

        foreach (var page in GetValues().AsPages(5).Take(3))
            foreach (var value in page)
                Console.Write(value + ",");
        // 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,
    }
}


Something to this effect

var page = (From c In db.Customers Order By c.ContactName, c.City Descending
                 Select c).Skip(50).Take(50)
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜