Déterminer si un IEnumerable<T> qui contient un objet d'un autre IEnumberable<T>
J'ai 2 IEnumerable<int>
IEnumerable<int> x;
IEnumerable<int> y;
Quel est le meilleur le meilleur moyen de déterminer si un int dans y est présent dans le x?
Actuellement, je suis en utilisant:
return x.Intersect<int>(y).Count() > 0;
Serait-il beaucoup plus rapide pour parcourir et de tester chacun d'eux?
foreach (int i in x)
{
foreach (int j in y)
{
if (i == j) return true;
}
}
return false;
Les listes sont relativement légères, avec pas plus de 50 entiers en x et 4 dans y si que les questions à l'examen.
OriginalL'auteur Adam | 2009-03-27
Vous devez vous connecter pour publier un commentaire.
Il serait plus rapide d'utiliser le
méthode au lieu de la
Count
méthode:Cela suppose que le
IEnumerable<int>
mise en œuvre n'est pas aussi mettre en œuvreICollection<int>
. Dans ce cas,Count
(dans le cas oùIEnumerable<T>
implémenteICollection<T>
) est un O(N) opérations, alorsAny
est toujours un O(1). (il vérifie uniquement pour une unique élément). Toutefois, le comportement deCount
est un détail d'implémentation, et vous ne devriez pas compter sur cela.J'ai écrit à ce sujet plus en profondeur dans un billet de blog qui va dans le détail sur l'utilisation de
Count()
vsAny()
. En résumé:Enumerable.Any
extension de la méthode de vérification de l'existence d'éléments dans la séquence.Enumerable.Count
méthode d'extension dans les comparaisons par rapport à zéro, comme les suivantes sont sémantiquement équivalentes:sequence.Count() == 0
!sequence.Any()
Enumerable.Count
méthode d'extension dans les comparaisons avec les “pas de zéro” de l'état, comme le sont sémantiquement équivalentes:sequence.Count != 0
sequence.Any()
OriginalL'auteur casperOne
EDIT: l'original de La réponse ci-dessous est vraiment affaire en termes de complexité. Si les séquences sont assez court, tous les appels par le biais de
GetNext()
, la construction d'unHashSet
etc sera effectivement plus cher que d'utiliserIntersect(y).Any()
. Toutefois, dans ce cas, les deux appels seront vraiment assez rapide tout de même.En d'autres termes,
Intersect(y).Any()
certainement évolue mieux que les deux séquences d'obtenir plus de temps, mais si vous êtes absolument sûr que les séquences sont courtes, la boucle imbriquée solution sera plus rapide.Réponse originale à cette question
Non,
Intersect()
sera plus rapide que les deux boucles de la solution - mais comme CasperOne écrit,Any()
sera plus rapide queCount()
, car il sera de sortie dès qu'il voit un élément.En supposant que les séquences de longueur N et M, Intersection sera
O(N + M)
alors que les deux boucles solution estO(N * M)
.Se croisent construit un
HashSet
de la "intérieure" de la séquence (cela prendO(M)
complexité) et puis parcourt l'extérieur de la séquence (qui prendO(N)
complexité), de produire tout élément qui se trouve dans le jeu. Ces résultats sont diffusés en continu - l'intérieur de la séquence sera évaluée lors de le premier élément est demandé deIntersect()
, mais cela ne va aussi loin que de trouver le premier match (le cas échéant). À l'aide deAny()
vous aurez un "début" s'il y a des matchs, donc nous n'avons pas besoin de prendre le nombre total de matches en considération lors de l'élaboration de la complexité.Streaming les résultats de LINQ roches - c'est bien la peine d'obtenir votre tête ronde (ainsi que l'exécution différée).
Voir mon edit pour l'explication 🙂
OriginalL'auteur Jon Skeet
Intersect
est d'accord, mais comme d'autres l'ont dit, je ne dirais pas.Count()
sur le résultat.La raison en est qui se Croisent ne pas créer l'intersection des deux listes. Il crée un
IEnumerable
qui est capable de l'énumération cette intersection, mais il ne fait pas d'énumérer ces résultats encore. La plupart des travaux est différée jusqu'au moment où vous avez enfin parcourir cette énumération.Le problème avec
Count
est qu'il ne itérer sur l'ensemble de l'énumération. Ainsi, non seulement faut-il toujours compter tous les résultats, mais il cause tout le travail impliqué dans le calcul de ces résultats à terme.Appel
Any
au contraire sera très rapide par comparaison, parce que vous permettra de calculer au plus une intersection résultat avant de retourner. Bien sûr, dans le cas où il n'y a pas de matches, il sera toujours nécessaire de réitérer la totalité de la liste. Cependant, ce n'est pas pire qu'avant. En fait, c'est encore plus rapide parce que Jon Skeet mentionné, laIntersect
fonction utilise un HashSet pour calculer les résultats, plutôt que de parcourir tout. Votre meilleure et la moyenne des cas sont considérablement améliorées.C'est comme la différence entre ces deux extraits:
.
Évidemment le 2ème est beaucoup plus rapide que la moyenne. La performance de
Any()
serait analogue (pas le même que, grâce à la HashSet) le 2ème extrait de code, tandis queCount()
serait analogue à la première.OriginalL'auteur Joel Coehoorn
Vous êtes mieux de faire ceci:
Cela s'arrête dès qu'il trouve un seul match, et arrêter l'énumération à travers les collections.
Non, grâce à la diffusion des résultats.
Intéressant, merci.
Josh: Regarder dans MSDN pour "l'Exécution Différée" dans LINQ. Il vaut la peine de prendre le temps de comprendre comment et pourquoi il fonctionne, et comment vous pouvez l'utiliser à votre avantage.
Ce n'est pas différé l'exécution en tant que telle - c'est le streaming les résultats. Ils sont un peu différentes. Par exemple, OrderBy est reportée, mais dès qu'elle est posée pour la première conséquence, il a de processus tous. Puis, il donne les résultats un par un, bien sûr. Se croisent est la moitié de flux de la moitié de la mémoire tampon.
OriginalL'auteur Reed Copsey
Cette question et la dernière réponse sont plus de 1 an de ma réponse; cependant, mes conclusions diffèrent de la accepté de répondre. Je trouve que la boucle est significativement plus rapide que l'utilisation se Croisent.(). Peut-être ma référence en matière de code n'est pas bon?
Voici le code que j'ai utilisé pour trouver le nombre d'itérations par seconde entre se Croisent, les boucles imbriquées, et une boucle avec IndexOf. S'il vous plaît excusez le VB. 😉
Mes résultats sur deux de 5 000 000 de point de tableaux. Plus d'itérations est mieux:
Mes résultats sur deux 50 tableaux. Plus d'itérations est mieux:
Un énorme problème, c'est que vous êtes en parcourant l'un des enumerables plusieurs fois, indépendamment de l'impact sur les performances, vous pourriez avoir des effets secondaires indésirables (que faire si il a été soutenu par une base de données d'appel?).
OriginalL'auteur Nick VanderPyle