Je voudrais quelque chose comme IEnumerable.FirstOrDefault
, mais je voudrais que la valeur par défaut soit retournée si length != 1
. Quelque chose comme v.Count() == 1 ? v[0] : default
. Mais je préférerais le faire sans convertir l'énumérable entier en tableau. Quel est le meilleur moyen d'obtenir ce comportement?Comment puis-je obtenir la première valeur d'un iEnumerable si la longueur est exactement une, ou par défaut sinon?
Répondre
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);
}
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.
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? –
@RuardvanElburg - merci pour la note (j'ai corrigé la faute de frappe). – MaKCbIMKo
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.
Je pense que c'est la meilleure réponse. – Bigeyes
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()'. –
@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
Certains énumérables peuvent même échouer la deuxième fois. –