How can I get every nth item from a List<T>?

C#LinqListLambda

C# Problem Overview


I'm using .NET 3.5 and would like to be able to obtain every *n*th item from a List. I'm not bothered as to whether it's achieved using a lambda expression or LINQ.

Edit

Looks like this question provoked quite a lot of debate (which is a good thing, right?). The main thing I've learnt is that when you think you know every way to do something (even as simple as this), think again!

C# Solutions


Solution 1 - C#

return list.Where((x, i) => i % nStep == 0);

Solution 2 - C#

I know it's "old school," but why not just use a for loop with stepping = n?

Solution 3 - C#

Sounds like

IEnumerator<T> GetNth<T>(List<T> list, int n) {
  for (int i=0; i<list.Count; i+=n)
    yield return list[i]
}

would do the trick. I do not see the need to use Linq or a lambda expressions.

EDIT:

Make it

public static class MyListExtensions {
  public static IEnumerable<T> GetNth<T>(this List<T> list, int n) {
    for (int i=0; i<list.Count; i+=n)
      yield return list[i];
  }
}

and you write in a LINQish way

from var element in MyList.GetNth(10) select element;

2nd Edit:

To make it even more LINQish

from var i in Range(0, ((myList.Length-1)/n)+1) select list[n*i];

Solution 4 - C#

You can use the Where overload which passes the index along with the element

var everyFourth = list.Where((x,i) => i % 4 == 0);

Solution 5 - C#

For Loop

for(int i = 0; i < list.Count; i += n)
    //Nth Item..

Solution 6 - C#

I think if you provide a linq extension, you should be able to operate on the least specific interface, thus on IEnumerable. Of course, if you are up for speed especially for large N you might provide an overload for indexed access. The latter removes the need of iterating over large amounts of not needed data, and will be much faster than the Where clause. Providing both overloads lets the compiler select the most suitable variant.

public static class LinqExtensions
{
    public static IEnumerable<T> GetNth<T>(this IEnumerable<T> list, int n)
    {
        if (n < 0)
            throw new ArgumentOutOfRangeException("n");
        if (n > 0)
        {
            int c = 0;
            foreach (var e in list)
            {
                if (c % n == 0)
                    yield return e;
                c++;
            }
        }
    }
    public static IEnumerable<T> GetNth<T>(this IList<T> list, int n)
    {
        if (n < 0)
            throw new ArgumentOutOfRangeException("n");
        if (n > 0)
            for (int c = 0; c < list.Count; c += n)
                yield return list[c];
    }
}

Solution 7 - C#

I'm not sure if it's possible to do with a LINQ expression, but I know that you can use the Where extension method to do it. For example to get every fifth item:

List<T> list = originalList.Where((t,i) => (i % 5) == 0).ToList();

This will get the first item and every fifth from there. If you want to start at the fifth item instead of the first, you compare with 4 instead of comparing with 0.

Solution 8 - C#

Imho no answer is right. All solutions begins from 0. But I want to have the real nth element

public static IEnumerable<T> GetNth<T>(this IList<T> list, int n)
{
	for (int i = n - 1; i < list.Count; i += n)
	    yield return list[i];
}

Solution 9 - C#

@belucha I like this, because the client code is very readable and the Compiler chooses the most efficient Implementation. I would build upon this by reducing the requirements to IReadOnlyList<T> and to save the Division for high-performance LINQ:

	public static IEnumerable<T> GetNth<T>(this IEnumerable<T> list, int n) {
		if (n <= 0) throw new ArgumentOutOfRangeException(nameof(n), n, null);
		int i = n;
		foreach (var e in list) {
			if (++i < n) { //save Division
				continue;
			}
			i = 0;
			yield return e;
		}
	}

	public static IEnumerable<T> GetNth<T>(this IReadOnlyList<T> list, int n
        , int offset = 0) { //use IReadOnlyList<T>
		if (n <= 0) throw new ArgumentOutOfRangeException(nameof(n), n, null);
		for (var i = offset; i < list.Count; i += n) {
			yield return list[i];
		}
	}

Solution 10 - C#

private static readonly string[] sequence = "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15".Split(',');

static void Main(string[] args)
{
    var every4thElement = sequence
      .Where((p, index) => index % 4 == 0);
    
    foreach (string p in every4thElement)
    {
        Console.WriteLine("{0}", p);
    }

    Console.ReadKey();
}

output

enter image description here

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPaul SuartView Question on Stackoverflow
Solution 1 - C#mqpView Answer on Stackoverflow
Solution 2 - C#Michael ToddView Answer on Stackoverflow
Solution 3 - C#MartinStettnerView Answer on Stackoverflow
Solution 4 - C#JaredParView Answer on Stackoverflow
Solution 5 - C#Quintin RobinsonView Answer on Stackoverflow
Solution 6 - C#beluchaView Answer on Stackoverflow
Solution 7 - C#GuffaView Answer on Stackoverflow
Solution 8 - C#user2340145View Answer on Stackoverflow
Solution 9 - C#SpocView Answer on Stackoverflow
Solution 10 - C#Anwar Ul-HaqView Answer on Stackoverflow