À travers un sous-ensemble Énumérer d'une collection en C #?
-
23-08-2019 - |
Question
Y at-il un bon moyen d'énumérer un sous-ensemble d'une collection en C #? C'est, j'ai une collection d'un grand nombre d'objets (par exemple, 1000), mais je voudrais énumérer seulement les éléments 250 - 340. Est-il un bon moyen d'obtenir un recenseur pour un sous-ensemble de la collection, sans en utilisant une autre collection?
Edit:. Aurait dû mentionner que ce utilise .NET Framework 2.0
La solution
Effectuez les opérations suivantes
var col = GetTheCollection();
var subset = col.Skip(250).Take(90);
Ou plus généralement
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);
Autres conseils
Je tiens à garder les choses simples (si vous ne devez pas nécessairement le recenseur):
for (int i = 249; i < Math.Min(340, list.Count); i++)
{
// do something with list[i]
}
L'adaptation du code original de Jared pour .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;
}
}
Et pour l'utiliser:
foreach (T item in GetRange(MyCollection, 250, 340))
{
// do something
}
L'adaptation du code de Jarad encore une fois, cette méthode extention vous obtiendrez un sous-ensemble qui est défini par élément , ne pas indexer.
//! 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;
}
}
}
Vous pourriez être en mesure de faire quelque chose avec LINQ. La façon dont je le faire est de mettre les objets dans un tableau, je peux choisir les éléments que je veux traiter en fonction de l'identifiant du tableau.
Si vous trouvez que vous devez faire une bonne quantité de découpage en dés et de trancher les listes et les collections, il est peut-être la peine de monter la courbe d'apprentissage dans la Bibliothèque Collection générique C5 .