TOC
LINQ:

Limiting data: the Take() & Skip() methods

So far, in this LINQ chapter of the tutorial, we have discovered several ways of working with data sources using LINQ. Now the time has come to see how we can limit the amount of data to work with. This is especially useful when using a database as a data source, because it often involves huge amounts of rows, which are resource consuming to fetch.

The methods we will discuss in this article are called Take() and Skip(), and in combination, they are great for doing stuff like pagination on a website. In fact, they are often used together, but they can of course be used alone as well. The Take() method will get you X number of items from the data source, while Skip() will allow you to ignore the first X items. A simple example could look like this:

List<string> names = new List<string>()
{
    "John Doe",
    "Jane Doe",
    "Joe Doe",
    "Jenna Doe",
};
var middleNames = names.Skip(1).Take(2).ToList();
foreach (var name in middleNames)
    Console.WriteLine(name);

We create a simple list of names and then, for the output, we skip the first name (Skip(1)) and then we take the next two names (Take(2)), basically leaving us with only the two middle names of the list.

Basic pagination with Skip() and Take()

As you can see, both the Take() and Skip() methods are very simple to use, but they are more interesting to demonstrate with more data than we have previously used, so I have taken the liberty of creating a slightly more complex example, which will better demonstrate how these methods can help you. First, here's the code for it:

using System;
using System.Globalization;
using System.Linq;
using System.Xml.Linq;

namespace LinqTakeSkip1
{
    class Program
    {
        static void Main(string[] args)
        {
            CultureInfo usCulture = new CultureInfo("en-US");
            XDocument xDoc = XDocument.Load("http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml");
            var cubeNodes = xDoc.Descendants().Where(n => n.Name.LocalName == "Cube" && n.Attribute("currency") != null).ToList();
            var currencyRateItems = cubeNodes.Select(node => new
            {
                Currency = node.Attribute("currency").Value,
                Rate = double.Parse(node.Attribute("rate").Value, usCulture)
            });


            int pageSize = 5, pageCounter = 0;
            var pageItems = currencyRateItems.Take(pageSize);
            while(pageItems.Count() > 0)
            {
                foreach (var item in pageItems)
                    Console.WriteLine(item.Currency + ": " + item.Rate.ToString("N2", usCulture));
                Console.WriteLine("Press any key to get the next items...");
                Console.ReadKey();
                pageCounter++;
                // Here's where we use the Skip() and Take() methods!
                pageItems = currencyRateItems.Skip(pageSize * pageCounter).Take(pageSize);
            }
            Console.WriteLine("Done!");
           
        }
    }
}

That's quite a bit of code, but let's run through it. In the first half, we parse a publically available XML source of currency exchange rates. This gives me the opportunity to briefly show you LINQ to XML, which is a very cool part of the LINQ eco-system. We will discuss LINQ to XML in another article, but for now, just know that we use it to pull the important nodes out of the XML source and put it into anonymous objects, consisting of the name and current exchange rate of the currency, which we'll use later on.

We now have a nice data source of currency information in the currencyRateItems variable. In the last half of the example, we use this source to do some simple pagination - we simply pull out 5 entries and then asks the user to press a key to get the next 5 (or however many there are left in the source). We do that by extracting the first 5 entries and then we use a while loop to continuously pull out the next 5 entries, until the source is empty. Getting the next 5 entries is done with a combination of Skip() and Take() - the entire basis of this article.

Summary

The Skip() and Take() methods are very simple to use, but nevertheless very useful in a lot of situations. As mentioned, they are often used together, but especially the Take() method can just as well be used alone.

This article has been fully translated into the following languages: Is your preferred language not on the list? Click here to help us translate this article into your language!