[c#] How to get first N elements of a list in C#?

I would like to use Linq to query a bus schedule in my project, so that at any time I can get the next 5 bus arrival times. How can I limit my query to the first 5 results?

More generally, how can I take a slice of a list in C#? (In Python I would use mylist[:5] to get the first 5 elements.)

This question is related to c#

The answer is


In case anyone is interested (even if the question does not ask for this version), in C# 2 would be: (I have edited the answer, following some suggestions)

myList.Sort(CLASS_FOR_COMPARER);
List<string> fiveElements = myList.GetRange(0, 5);

To take first 5 elements better use expression like this one:

var firstFiveArrivals = myList.Where([EXPRESSION]).Take(5);

or

var firstFiveArrivals = myList.Where([EXPRESSION]).Take(5).OrderBy([ORDER EXPR]);

It will be faster than orderBy variant, because LINQ engine will not scan trough all list due to delayed execution, and will not sort all array.

class MyList : IEnumerable<int>
{

    int maxCount = 0;

    public int RequestCount
    {
        get;
        private set;
    }
    public MyList(int maxCount)
    {
        this.maxCount = maxCount;
    }
    public void Reset()
    {
        RequestCount = 0;
    }
    #region IEnumerable<int> Members

    public IEnumerator<int> GetEnumerator()
    {
        int i = 0;
        while (i < maxCount)
        {
            RequestCount++;
            yield return i++;
        }
    }

    #endregion

    #region IEnumerable Members

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        throw new NotImplementedException();
    }

    #endregion
}
class Program
{
    static void Main(string[] args)
    {
        var list = new MyList(15);
        list.Take(5).ToArray();
        Console.WriteLine(list.RequestCount); // 5;

        list.Reset();
        list.OrderBy(q => q).Take(5).ToArray();
        Console.WriteLine(list.RequestCount); // 15;

        list.Reset();
        list.Where(q => (q & 1) == 0).Take(5).ToArray();
        Console.WriteLine(list.RequestCount); // 9; (first 5 odd)

        list.Reset();
        list.Where(q => (q & 1) == 0).Take(5).OrderBy(q => q).ToArray();
        Console.WriteLine(list.RequestCount); // 9; (first 5 odd)
    }
}

To take first 5 elements better use expression like this one:

var firstFiveArrivals = myList.Where([EXPRESSION]).Take(5);

or

var firstFiveArrivals = myList.Where([EXPRESSION]).Take(5).OrderBy([ORDER EXPR]);

It will be faster than orderBy variant, because LINQ engine will not scan trough all list due to delayed execution, and will not sort all array.

class MyList : IEnumerable<int>
{

    int maxCount = 0;

    public int RequestCount
    {
        get;
        private set;
    }
    public MyList(int maxCount)
    {
        this.maxCount = maxCount;
    }
    public void Reset()
    {
        RequestCount = 0;
    }
    #region IEnumerable<int> Members

    public IEnumerator<int> GetEnumerator()
    {
        int i = 0;
        while (i < maxCount)
        {
            RequestCount++;
            yield return i++;
        }
    }

    #endregion

    #region IEnumerable Members

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        throw new NotImplementedException();
    }

    #endregion
}
class Program
{
    static void Main(string[] args)
    {
        var list = new MyList(15);
        list.Take(5).ToArray();
        Console.WriteLine(list.RequestCount); // 5;

        list.Reset();
        list.OrderBy(q => q).Take(5).ToArray();
        Console.WriteLine(list.RequestCount); // 15;

        list.Reset();
        list.Where(q => (q & 1) == 0).Take(5).ToArray();
        Console.WriteLine(list.RequestCount); // 9; (first 5 odd)

        list.Reset();
        list.Where(q => (q & 1) == 0).Take(5).OrderBy(q => q).ToArray();
        Console.WriteLine(list.RequestCount); // 9; (first 5 odd)
    }
}

In case anyone is interested (even if the question does not ask for this version), in C# 2 would be: (I have edited the answer, following some suggestions)

myList.Sort(CLASS_FOR_COMPARER);
List<string> fiveElements = myList.GetRange(0, 5);

In case anyone is interested (even if the question does not ask for this version), in C# 2 would be: (I have edited the answer, following some suggestions)

myList.Sort(CLASS_FOR_COMPARER);
List<string> fiveElements = myList.GetRange(0, 5);

To take first 5 elements better use expression like this one:

var firstFiveArrivals = myList.Where([EXPRESSION]).Take(5);

or

var firstFiveArrivals = myList.Where([EXPRESSION]).Take(5).OrderBy([ORDER EXPR]);

It will be faster than orderBy variant, because LINQ engine will not scan trough all list due to delayed execution, and will not sort all array.

class MyList : IEnumerable<int>
{

    int maxCount = 0;

    public int RequestCount
    {
        get;
        private set;
    }
    public MyList(int maxCount)
    {
        this.maxCount = maxCount;
    }
    public void Reset()
    {
        RequestCount = 0;
    }
    #region IEnumerable<int> Members

    public IEnumerator<int> GetEnumerator()
    {
        int i = 0;
        while (i < maxCount)
        {
            RequestCount++;
            yield return i++;
        }
    }

    #endregion

    #region IEnumerable Members

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        throw new NotImplementedException();
    }

    #endregion
}
class Program
{
    static void Main(string[] args)
    {
        var list = new MyList(15);
        list.Take(5).ToArray();
        Console.WriteLine(list.RequestCount); // 5;

        list.Reset();
        list.OrderBy(q => q).Take(5).ToArray();
        Console.WriteLine(list.RequestCount); // 15;

        list.Reset();
        list.Where(q => (q & 1) == 0).Take(5).ToArray();
        Console.WriteLine(list.RequestCount); // 9; (first 5 odd)

        list.Reset();
        list.Where(q => (q & 1) == 0).Take(5).OrderBy(q => q).ToArray();
        Console.WriteLine(list.RequestCount); // 9; (first 5 odd)
    }
}

Like pagination you can use below formule for taking slice of list or elements:

var slice = myList.Skip((pageNumber - 1) * pageSize)
                  .Take(pageSize);

Example 1: first five items

var pageNumber = 1;
var pageSize = 5;

Example 2: second five items

var pageNumber = 2;
var pageSize = 5;

Example 3: third five items

var pageNumber = 3;
var pageSize = 5;

If notice to formule parameters pageSize = 5 and pageNumber is changing, if you want to change number of items in slicing you change pageSize.


In case anyone is interested (even if the question does not ask for this version), in C# 2 would be: (I have edited the answer, following some suggestions)

myList.Sort(CLASS_FOR_COMPARER);
List<string> fiveElements = myList.GetRange(0, 5);

        dataGridView1.DataSource = (from S in EE.Stagaire
                                    join F in EE.Filiere on
                                    S.IdFiliere equals F.IdFiliere
                                    where S.Nom.StartsWith("A")
                                    select new
                                    {
                                        ID=S.Id,
                                        Name = S.Nom,
                                        Prénon= S.Prenon,
                                        Email=S.Email,
                                        MoteDePass=S.MoteDePass,
                                        Filiere = F.Filiere1
                                    }).Take(1).ToList();