2017-02-19 3 views

Répondre

7

C'est une bonne idée d'éviter de répéter l'énumération plus d'une fois car tous les énumérables ne répètent pas les mêmes valeurs.

Afin de vous assurer que votre dénombrable retourne seulement 1 élément, il est le plus efficace de prendre les deux premiers éléments du dénombrable et convertir le résultat dans un tableau. Si le tableau a alors deux éléments, vous savez que l'énumérable a plus d'un élément sans itération de l'entier énumérable. Il est possible qu'un énumérable soit infiniment long.

Alors, voici comment faire:

public static T OneOnlyThenFirstOrDefault<T>(this IEnumerable<T> source) 
{ 
    var beginning = source.Take(2).ToArray(); 
    return beginning.Length == 1 ? beginning[0] : default(T); 
} 
+0

La conversion en tableau est-elle nécessaire? Basé sur [cette réponse à une question connexe] (http://stackoverflow.com/a/1993398/2137382) Je pense que vous pouvez simplement vérifier si 'Take (2) .Count() == 1', et si oui , retourne 'source.Single()'. –

+3

@JoeSewell - La conversion en tableau est nécessaire. Si vous faites '.Take (2) .Count()' et ensuite '.Single()', vous itérez l'énumérable deux fois et il n'y a aucune garantie qu'un énumérable produise toujours les mêmes valeurs à chaque fois. – Enigmativity

+2

Certains énumérables peuvent même échouer la deuxième fois. –

0

Avez-vous essayé d'écrire une méthode d'extension personnalisée, quelque chose comme:

public static TSource MyFirstOrDefault<TSource>(this IEnumerable<TSource> source) 
{ 
    return source.Count() == 1 ? source.First() : default(TSource); 
} 

mais vous devez garder à l'esprit que les méthodes Count() et First() devront instancier la collection intérieure d'éléments afin d'obtenir la compter (ou le premier élément).

Espérons que cela vous aidera.

+1

Cela va générer une exception. Il n'y a pas de premier item quand le compte est nul. En plus de cela, quelle valeur est retournée quand la source a deux éléments? –

+0

@RuardvanElburg - merci pour la note (j'ai corrigé la faute de frappe). – MaKCbIMKo

9

la mise en œuvre de Microsoft Enumerable.FirstOrDefault travaille directement avec le recenseur sous-jacent. Le vôtre peut aussi:

public static T FirstIfOnlyOne<T>(this IEnumerable<T> source, T defaultValue = default(T)) 
{ 
    // (Null check and IList<T> optimization omitted...) 

    using (IEnumerator<T> enumerator = source.GetEnumerator()) 
    { 
     if (enumerator.MoveNext()) // Is there at least one item? 
     { 
      T item = enumerator.Current; // Save it. 
      if (!enumerator.MoveNext()) // Is that it? 
       return item; 
     } 
    } 
    return defaultValue; 
} 

Ceci est probablement l'implémentation la plus efficace possible.

+1

Je pense que c'est la meilleure réponse. – Bigeyes