Quelle est la «meilleure» façon (en tenant compte à la fois de la vitesse et de la lisibilité) pour déterminer si une liste est vide? Même si la liste est de type IEnumerable<T>
et n'a pas de propriété Count.
En ce moment, je me balance entre ceci:
if (myList.Count() == 0) { ... }
et ça:
if (!myList.Any()) { ... }
Je suppose que la deuxième option est plus rapide, car elle reviendra avec un résultat dès qu'elle verra le premier élément, tandis que la deuxième option (pour un IEnumerable) devra visiter chaque élément pour renvoyer le décompte.
Cela étant dit, la deuxième option vous paraît-elle aussi lisible? Lequel préférez-vous? Ou pouvez-vous penser à une meilleure façon de tester une liste vide?
La réponse de Edit @ lassevk semble être la plus logique, associée à un peu de vérification à l'exécution pour utiliser un nombre mis en cache si possible, comme ceci:
public static bool IsEmpty<T>(this IEnumerable<T> list)
{
if (list is ICollection<T>) return ((ICollection<T>)list).Count == 0;
return !list.Any();
}
is
etcast
mais utiliseras
etnull
vérifier:ICollection<T> collection = list as ICollection<T>; if (collection != null) return colllection.Count;
list.Any()
équivalent àlist.IsEmpty
? La méthode du framework doit être optimisée - cela ne vaut la peine d'en écrire une nouvelle que si vous avez compris que c'est un goulot d'étranglement de performance.IsEmpty
méthode d'extension. github.com/dotnet/corefx/issues/35054 S'il vous plaît vérifier et voter si vous aimez et acceptez.Réponses:
Vous pouvez faire ceci:
Modifier : notez que la simple utilisation de la méthode .Count sera rapide si la source sous-jacente possède en fait une propriété Count rapide. Une optimisation valide ci-dessus serait de détecter quelques types de base et d'utiliser simplement la propriété .Count de ceux-ci, au lieu de l'approche .Any (), puis de revenir à .Any () si aucune garantie ne peut être faite.
la source
IsNullOrEmpty()
.return !source?.Any() ?? true;
Je ferais un petit ajout au code sur lequel vous semblez avoir choisi: vérifiez également
ICollection
, car cela est également implémenté par certaines classes génériques non obsolètes (c'est-à-direQueue<T>
etStack<T>
). J'utiliserais égalementas
au lieu deis
car il est plus idiomatique et s'est avéré plus rapide .la source
NotSupportedException
ouNotImplementedException
. J'ai utilisé votre exemple de code pour la première fois lorsque j'ai découvert qu'une collection que j'utilisais a jeté une exception pour Count (qui savait ...).Cela vous surprend-il? J'imagine que pour les
IList
implémentations,Count
lit simplement le nombre d'éléments directement toutAny
en interrogeant laIEnumerable.GetEnumerator
méthode, créez une instance et appelezMoveNext
au moins une fois./ EDIT @Matt:
Oui, bien sûr. C'est ce que je voulais dire. En fait, il utilise à la
ICollection
place deIList
mais le résultat est le même.la source
Je viens de rédiger un test rapide, essayez ceci:
Le second est presque trois fois plus lent :)
Essayer à nouveau le test du chronomètre avec une pile ou un tableau ou d'autres scénarios, cela dépend vraiment du type de liste qu'il semble - car ils prouvent que Count est plus lent.
Donc je suppose que cela dépend du type de liste que vous utilisez!
(Juste pour souligner, j'ai mis plus de 2000 objets dans la liste et le comptage était encore plus rapide, contrairement aux autres types)
la source
Enumerable.Count<T>()
a un traitement spécial pourICollection<T>
. Si vous essayez ceci avec autre chose qu'une liste de base, j'espère que vous verrez des résultats significativement différents (plus lents).Any()
restera à peu près le même, cependant.Enumerable.Any<T>()
pourICollection<T>
? Sûrement le sans paramètreAny()
pourrait simplement vérifier laCount
propriétéICollection<T>
aussi?List.Count
est O (1) selon la documentation de Microsoft:http://msdn.microsoft.com/en-us/library/27b47ht3.aspx
alors utilise juste
List.Count == 0
c'est beaucoup plus rapide qu'une requêteEn effet, il a un membre de données appelé Count qui est mis à jour chaque fois que quelque chose est ajouté ou supprimé de la liste, de sorte que lorsque vous l'appelez,
List.Count
il n'a pas à parcourir chaque élément pour l'obtenir, il renvoie simplement le membre de données.la source
La deuxième option est beaucoup plus rapide si vous avez plusieurs éléments.
Any()
retourne dès qu'un article est trouvé.Count()
doit continuer à parcourir toute la liste.Par exemple, supposons que l'énumération contienne 1000 éléments.
Any()
vérifierait le premier, puis retournerait vrai.Count()
retournerait 1000 après avoir parcouru toute l'énumération.C'est potentiellement pire si vous utilisez l'un des remplacements de prédicat - Count () doit toujours vérifier chaque élément, même s'il n'y a qu'une seule correspondance.
Vous vous habituez à utiliser Any one - cela a du sens et est lisible.
Une mise en garde - si vous avez une liste, plutôt qu'un simple IEnumerable, utilisez la propriété Count de cette liste.
la source
@Konrad ce qui me surprend, c'est que dans mes tests, je passe la liste dans une méthode qui accepte
IEnumerable<T>
, donc le runtime ne peut pas l'optimiser en appelant la méthode d'extension Count () pourIList<T>
.Je ne peux que supposer que la méthode d'extension Count () pour IEnumerable fait quelque chose comme ceci:
... en d'autres termes, un peu d'optimisation du runtime pour le cas particulier de
IList<T>
./ EDIT @Konrad +1 compagnon - vous avez raison, il est plus probable que vous soyez allumé
ICollection<T>
.la source
Ok, alors qu'en est-il de celui-ci?
EDIT: Je viens de réaliser que quelqu'un a déjà esquissé cette solution. Il a été mentionné que la méthode Any () le fera, mais pourquoi ne pas le faire vous-même? Cordialement
la source
using
bloc, sinon vous avez construit unIDisposable
objet et l' avez ensuite abandonné. Ensuite, bien sûr, cela devient plus succinct lorsque vous utilisez la méthode d'extension qui existe déjà et que vous la modifiez simplement enreturn !enumerable.Any()
(ce qui fait précisément cela).Any()
exécute exactement cela, donc ajouter exactement la même méthode avec un autre nom sera juste déroutant.Une autre idée:
Cependant, j'aime plus l'approche Any ().
la source
C'était essentiel pour que cela fonctionne avec Entity Framework:
la source
Si je vérifie avec Count () Linq exécute un "SELECT COUNT (*) .." dans la base de données, mais que je dois vérifier si les résultats contiennent des données, j'ai résolu d'introduire FirstOrDefault () au lieu de Count ();
Avant
Après
la source
la source
Voici ma mise en œuvre de la réponse de Dan Tao, permettant un prédicat:
la source
la source
myList.ToList().Count == 0
. C'est toutla source
Cette méthode d'extension fonctionne pour moi:
la source