1

I have a C# List<T> of items. I want to iterate from a certain index to the end of the List<T> of items. Can I do this using the foreach syntax?

 List<T> list = ...

 foreach (var item in ???) 
 {
    ...
 }

or any other method?

e.g. from List.Count - 50 until the end (I only want the last 50 items)

Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
Harry Boy
  • 4,159
  • 17
  • 71
  • 122

5 Answers5

11

Try:

foreach (var item in list.Skip(Math.Max(0, list.Count - 50)))

If you know the list will be at least 50 long, you can avoid the range checking:

foreach (var item in list.Skip(list.Count-50))

Although I'd DEFINITELY just write the for loop and avoid any fancy stuff:

for (int i = Math.Max(0, list.Count - 50); i < list.Count; ++i)
{
    // Do something with list[i]
}

Non-range-checked version:

for (int i = list.Count-50; i < list.Count; ++i)
{
    // Do something with list[i]
}
Matthew Watson
  • 104,400
  • 10
  • 158
  • 276
7

Try to use something like:

newList = Enumerable.Reverse(list).Take(50).Reverse().ToList();
Roman Marusyk
  • 23,328
  • 24
  • 73
  • 116
7

Since Skip actually enumerates items, it's not very efficient in case of List<T>:

    public static IEnumerable<TSource> Skip<TSource>(this IEnumerable<TSource> source, int count) {
        if (source == null) throw Error.ArgumentNull("source");
        return SkipIterator<TSource>(source, count);
    }

    ...

    static IEnumerable<TSource> SkipIterator<TSource>(IEnumerable<TSource> source, int count) {
        using (IEnumerator<TSource> e = source.GetEnumerator()) {
            while (count > 0 && e.MoveNext()) count--;
            if (count <= 0) {
                while (e.MoveNext()) yield return e.Current;
            }
        }
    }

see reference source http://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs,90ccdbd47b57182e for details; if the initial list is very long one, I suggest using for loop and emulate foreach one:

// the simplest in case list.Count >= 50 
// foreach (var item in ...) {...} emulation
for (int i = list.Count - 50; i < list.Count; ++i) {
  var item = list[i];

  ...
}

For arbitrary size List (can have fewer tan 50 items)

for (int i = Math.Max(list.Count - 50, 0); i < list.Count; ++i) {
  var item = list[i];

  ...
}
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
2
myList.Reverse();          // Reverse the list
lastFive = myList.Take(5); // Take the first 5 elements from the list.
myList.Reverse();          // Restore the list to its original order.
abelenky
  • 63,815
  • 23
  • 109
  • 159
2

Given that you have an IList<T> (assuming from your prose), then you can use a for loop to grab the last n pretty easily. This will still be lazily evaluated like much of LINQ -

public static IEnumerable<T> LastN<T>(this IList<T> list, int n)
{
    if (list == null) 
    {
        throw new ArgumentNullException("list");
    }

    if (list.Count - n < 0) 
    {
        n = list.Count;
    }

    for (var i = list.Count - n; i < list.Count; i++) 
    {
        yield return list[i];
    }
}

// use 
var tail50 = myList.LastN(50); 

This will also well suited for an ICollection<T>.

There are some collection types that implement ICollection<T>, such as LinkedList<T>, that if you know about their concrete types, there may be more efficient ways to accomplish what you're needing. (in this case, the code above would be generally inefficient for a LinkedList<T>).

One thing to keep in mind when working with collections is IEnumerable<T> and the possibility that it's an infinite sequence. In those cases, unless you know the concrete type of the IEnumerable<T> or through other means know that it's finite, it's possibly best to re-think the idea of getting the "last n items", as it may not even be possible.

jdphenix
  • 15,022
  • 3
  • 41
  • 74
  • 1
    +1 Nice solution. Personnaly i would expect .LastN() to return the last n or, if there is less items, all the items. – aprovent Sep 05 '16 at 16:29
  • I tend to agree with you, and adding another precondition invariant seems excessive anyhow. – jdphenix Sep 05 '16 at 22:45