2009-05-19 10 views
9

Есть ли способ перечислить только подмножество коллекции в C#? То есть у меня есть коллекция большого количества объектов (скажем, 1000), но я бы хотел перечислить только элементы 250 - 340. Есть ли хороший способ получить Enumerator для подмножества коллекции без используя другую коллекцию?Перечислить через подмножество коллекции в C#?

Редактировать: следует упомянуть, что это использует .NET Framework 2.0.

ответ

32

Попробуйте следующие действия

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

или в более общем

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 Раствора

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); 
+0

Мне нравится этот способ расширения. –

+0

Извините, это использует .NET 2.0; skip недоступен. Если бы это было в .NET 3.5, это было бы золотым. –

+1

@McWafflestix добавила 2.0 решение – JaredPar

0

Вы могли бы быть в состоянии сделать что-то с Linq. Я бы это сделал, чтобы поместить объекты в массив, затем я могу выбрать, какие элементы я хочу обработать на основе идентификатора массива.

0

Если вы обнаружите, что вам нужно сделать достаточное количество нарезки и нарезки списков и коллекций, возможно, стоит подняться на кривой обучения в the C5 Generic Collection Library.

3

Я хотел бы сохранить его простым (если вы не обязательно должны перечислителем):

for (int i = 249; i < Math.Min(340, list.Count); i++) 
{ 
    // do something with list[i] 
} 
+0

Это намного проще, чем принятый ответ ... Также, как я вижу, это имеет то преимущество, если мы хотим получить элементы, которые находятся ближе к концу действительно большого списка. Принятый ответ не изменился бы с самого начала. ... Учитывая все это, я смущен, почему у этого ответа так мало оборотов. Не хватает ли чего-то технического ответа? Или это был случай, когда вы отправляли этот ответ после того, как был принят другой, так что многие люди его не рассматривали. –

+0

@AmithGeorge Большинство других ответов работают со всеми коллекциями, которые реализуют IEnumerable. Этот ответ полезен только для тех, кто хочет реализовать IList или какой-либо другой числовой индекс/индекс. Надеюсь, это прояснит ситуацию. – CanadaIT

2

Адаптация исходного кода Джареда для .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; 
    } 
} 

И использовать его:

foreach (T item in GetRange(MyCollection, 250, 340)) 
{ 
    // do something 
} 
1

Адаптация кода Джарад еще раз, этот метод продление получит вам подмножество, которое определяется шт., нет указатель.

//! 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; 
     } 
    } 
}