13

Is there a good way to enumerate through only a subset of a Collection in C#? That is, I have a collection of a large number of objects (say, 1000), but I'd like to enumerate through only elements 250 - 340. Is there a good way to get an Enumerator for a subset of the collection, without using another Collection?

Edit: should have mentioned that this is using .NET Framework 2.0.

Paul Sonier
  • 38,903
  • 3
  • 77
  • 117

6 Answers6

39

Try the following

var col = GetTheCollection();
var subset = col.Skip(250).Take(90);

Or more generally

public static IEnumerable<T> GetRange(this IEnumerable<T> source, int start, int end) {
  // Error checking removed
  return source.Skip(start).Take(end - start);
}

EDIT 2.0 Solution

public static IEnumerable<T> GetRange<T>(IEnumerable<T> source, int start, int end ) {
  using ( var e = source.GetEnumerator() ){ 
    var i = 0;
    while ( i < start && e.MoveNext() ) { i++; }
    while ( i < end && e.MoveNext() ) { 
      yield return e.Current;
      i++;
    }
  }      
}

IEnumerable<Foo> col = GetTheCollection();
IEnumerable<Foo> range = GetRange(col, 250, 340);
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
3

I like to keep it simple (if you don't necessarily need the enumerator):

for (int i = 249; i < Math.Min(340, list.Count); i++)
{
    // do something with list[i]
}
Fredrik Mörk
  • 155,851
  • 29
  • 291
  • 343
  • This is so much simpler than the accepted answer... Also as I see it, this has the advantage if we are to get items which are towards the end of a really large list. The accepted answer would unneccessarily traverse right from the beginning. ... Considering all this, am confused why this answer has so few upvotes. Am I missing something technical about this answer? Or was it just a case of you posting this answer after the other one was accepted, so not many people actually viewed it. – Amith George Sep 04 '11 at 05:51
  • @AmithGeorge Most of the other answers work with all collections that implement IEnumerable. This answer is only of use to someone that wants to implement IList or some other numeric indexer/subscript. I hope that clears things up. –  Apr 02 '15 at 18:39
3

Adapting Jared's original code for .Net 2.0:

IEnumerable<T> GetRange(IEnumerable<T> source, int start, int end)
{
    int i = 0;
    foreach (T item in source)
    {
        i++;
        if (i>end) yield break;
        if (i>start) yield return item;
    }
}

And to use it:

 foreach (T item in GetRange(MyCollection, 250, 340))
 {
     // do something
 }
Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
2

Adapting Jarad's code once again, this extention method will get you a subset that is defined by item, not index.

    //! Get subset of collection between \a start and \a end, inclusive
    //! Usage
    //! \code
    //! using ExtensionMethods;
    //! ...
    //! var subset = MyList.GetRange(firstItem, secondItem);
    //! \endcode
class ExtensionMethods
{
    public static IEnumerable<T> GetRange<T>(this IEnumerable<T> source, T start, T end)
    {
#if DEBUG
        if (source.ToList().IndexOf(start) > source.ToList().IndexOf(end))
            throw new ArgumentException("Start must be earlier in the enumerable than end, or both must be the same");
#endif
        yield return start;

        if (start.Equals(end))
            yield break;                                                    //start == end, so we are finished here

        using (var e = source.GetEnumerator())
        { 
            while (e.MoveNext() && !e.Current.Equals(start));               //skip until start                
            while (!e.Current.Equals(end) && e.MoveNext())                  //return items between start and end
                yield return e.Current;
        }
    }
}
Jim
  • 21
  • 2
0

You might be able to do something with Linq. The way I would do this is to put the objects into an array, then I can choose which items I want to process based on the array id.

Jeff
  • 5,913
  • 2
  • 28
  • 30
0

If you find that you need to do a fair amount of slicing and dicing of lists and collections, it might be worth climbing the learning curve into the C5 Generic Collection Library.

Yes - that Jake.
  • 16,725
  • 14
  • 70
  • 96