Comment obtenir le premier élément d'un IEnumerable <T> dans .net?

157

Je veux souvent saisir le premier élément d'un IEnumerable<T>.net, et je n'ai pas trouvé de moyen sympa de le faire. Le meilleur que j'ai trouvé est:

foreach(Elem e in enumerable) {
  // do something with e
  break;
}

Beurk! Alors, y a-t-il une bonne façon de faire cela?

TimK
la source

Réponses:

242

Si vous pouvez utiliser LINQ, vous pouvez utiliser:

var e = enumerable.First();

Cela lèvera une exception si enumerable est vide: auquel cas vous pouvez utiliser:

var e = enumerable.FirstOrDefault();

FirstOrDefault()retournera default(T)si l'énumérable est vide, ce qui sera nullpour les types référence ou la «valeur zéro» par défaut pour les types valeur.

Si vous ne pouvez pas utiliser LINQ, votre approche est techniquement correcte et n'est pas différente de la création d'un énumérateur à l'aide des méthodes GetEnumeratoret MoveNextpour récupérer le premier résultat (cet exemple suppose que énumérable est un IEnumerable<Elem>):

Elem e = myDefault;
using (IEnumerator<Elem> enumer = enumerable.GetEnumerator()) {
    if (enumer.MoveNext()) e = enumer.Current;
}

Joel Coehoorn mentionné .Single()dans les commentaires; cela fonctionnera également, si vous vous attendez à ce que votre énumérable contienne exactement un élément - cependant, il lèvera une exception s'il est vide ou plus grand qu'un élément. Il existe une SingleOrDefault()méthode correspondante qui couvre ce scénario de la même manière que FirstOrDefault(). Cependant, David B explique que cela SingleOrDefault()peut toujours lever une exception dans le cas où l'énumérable contient plusieurs éléments.

Edit: Merci Marc Gravell d' avoir souligné que je dois me débarrasser de mon IEnumeratorobjet après l'avoir utilisé - j'ai édité l'exemple non LINQ pour afficher le usingmot - clé pour implémenter ce modèle.

Erik Forbes
la source
2
Il convient de souligner que SingleOrDefault renverra 1) Le seul élément s'il n'y a qu'un seul élément. 2) nul s'il n'y a aucun élément. 3) lancer une exception s'il y a plus d'un élément.
Amy B
Bon appel David B - a ajouté une note.
Erik Forbes
36

Juste au cas où vous utilisez .NET 2.0 et n'avez pas accès à LINQ:

 static T First<T>(IEnumerable<T> items)
 {
     using(IEnumerator<T> iter = items.GetEnumerator())
     {
         iter.MoveNext();
         return iter.Current;
     }
 }

Cela devrait faire ce que vous recherchez ... il utilise des génériques afin que vous puissiez obtenir le premier élément sur n'importe quel type IEnumerable.

Appelez ça comme ça:

List<string> items = new List<string>() { "A", "B", "C", "D", "E" };
string firstItem = First<string>(items);

Ou

int[] items = new int[] { 1, 2, 3, 4, 5 };
int firstItem = First<int>(items);

Vous pouvez le modifier assez facilement pour imiter la méthode d'extension IEnumerable.ElementAt () de .NET 3.5:

static T ElementAt<T>(IEnumerable<T> items, int index)
{
    using(IEnumerator<T> iter = items.GetEnumerator())
    {
        for (int i = 0; i <= index; i++, iter.MoveNext()) ;
        return iter.Current;
    }
} 

Appelant ça comme ça:

int[] items = { 1, 2, 3, 4, 5 };
int elemIdx = 3;
int item = ElementAt<int>(items, elemIdx);

Bien sûr , si vous n'avez accès à LINQ, alors il y a beaucoup de bonnes réponses déjà ... affiché

BenAlabaster
la source
Oups, bien sûr, vous avez raison, merci. J'ai corrigé mes exemples.
BenAlabaster
Si vous êtes sur 2.0, vous n'avez pas non plus var.
récursif le
1
Eh bien, je suppose que si vous voulez devenir capricieux, je les déclarerai correctement: P
BenAlabaster
En tant que personne coincée avec .NET 2.0, cela a été grandement apprécié! Gloire.
kayleeFrye_onDeck
26

Eh bien, vous n'avez pas spécifié la version de .Net que vous utilisez.

En supposant que vous ayez 3.5, une autre méthode est la méthode ElementAt:

var e = enumerable.ElementAt(0);
Adam Lassek
la source
2
ElementAt (0), agréable et simple.
JMD
6

FirstOrDefault ?

Elem e = enumerable.FirstOrDefault();
//do something with e
Amy B
la source
1

essaye ça

IEnumberable<string> aa;
string a = (from t in aa where t.Equals("") select t.Value).ToArray()[0];
Daodao
la source
0

Utilisez FirstOrDefault ou une boucle foreach comme déjà mentionné. Il faut éviter de récupérer manuellement un énumérateur et d'appeler Current. foreach supprimera votre énumérateur pour vous s'il implémente IDisposable. Lorsque vous appelez MoveNext et Current, vous devez le supprimer manuellement (si cela est possible).

Mouk
la source
1
Quelle preuve y a-t-il que le recenseur devrait être évité? Les tests de performance sur ma machine indiquent qu'elle a un gain de performance d'environ 10% par rapport à chacun.
BenAlabaster
Cela dépend de ce que vous énumérez. Un Erumerator pourrait fermer la connexion à la base de données, fush et fermer le descripteur de fichier, libérer certains objets verrouillés, etc. Ne pas éliminer un énumérateur d'une liste d'entiers ne sera pas dangereux, je suppose.
Mouk
0

Si votre IEnumerable ne l'expose pas <T>et que Linq échoue, vous pouvez écrire une méthode à l'aide de la réflexion:

public static T GetEnumeratedItem<T>(Object items, int index) where T : class
{
  T item = null;
  if (items != null)
  {
    System.Reflection.MethodInfo mi = items.GetType()
      .GetMethod("GetEnumerator");
    if (mi != null)
    {
      object o = mi.Invoke(items, null);
      if (o != null)
      {
        System.Reflection.MethodInfo mn = o.GetType()
          .GetMethod("MoveNext");
        if (mn != null)
        {
          object next = mn.Invoke(o, null);
          while (next != null && next.ToString() == "True")
          {
            if (index < 1)
            {
              System.Reflection.PropertyInfo pi = o
                .GetType().GetProperty("Current");
              if (pi != null) item = pi
                .GetValue(o, null) as T;
              break;
            }
            index--;
          }
        }
      }
    }
  }
  return item;
}
CZahrobsky
la source
0

vous pouvez également essayer la version plus générique qui vous donne le ième élément

enumerable.ElementAtOrDefault (i));

J'espère que ça aide

personne au hasard sur Internet
la source