Peut LINQ utiliser les binaires de recherche lorsque la collection est ordonnée?
Je peux en quelque sorte "instruire" LINQ to utiliser les binaires de recherche lors de la collecte que j'essaie de recherche est commandé. Je suis à l'aide d'un ObservableCollection<T>
, peuplé de données ordonnées, et je suis en train d'utiliser Énumérable.La première(<Prédicat>). Dans mon prédicat, je suis le filtrage par la valeur du champ de ma collection triée par.
- Salut, je viens de la trouver et de la correction d'un bug dans mon implémentation, dans le cas où vous l'utilisez...
Vous devez vous connecter pour publier un commentaire.
Autant que je sache, il n'est pas possible avec les méthodes intégrées. Cependant, il serait relativement facile d'écrire une méthode d'extension qui vous permettra d'écrire quelque chose comme ça :
(en supposant, bien sûr, que vous collection met en œuvre IList ; il n'y a aucun moyen d'effectuer une recherche binaire si vous ne pouvez pas accéder aux éléments de façon aléatoire)
Voici un exemple d'implémentation :
(pas testé... quelques ajustements pourraient être nécessaires)testé et corrigé 😉Le fait qu'il jette un
InvalidOperationException
peut sembler étrange, mais c'est ce queEnumerable.First
ne quand il n'y a aucun élément correspondant.mid
calcul:int mid = min + ((max - min) / 2);
. Check this out: googleresearch.blogspot.ae/2006/06/...min + ((max - min) / 2)
est le même que(2 * min + (max - min)) / 2
, ce qui réduit à(min + max) / 2
Accepté la réponse est très bonne.
Cependant, j'ai besoin que l'BinarySearch renvoie l'index du premier élément qui est plus, que la
List<T>.BinarySearch()
n'.Donc j'ai regardé sa mise en œuvre en utilisant ILSpy, puis je l'ai modifié pour avoir un sélecteur de paramètre. J'espère que ce sera utile à quelqu'un qu'il l'est pour moi:
Bien, vous pouvez écrire votre propre méthode d'extension de plus de
ObservableCollection<T>
- mais alors, qui sera utilisé pour toutObservableCollection<T>
où votre méthode d'extension est disponible, sans savoir si c'est triée ou non.Il faudrait aussi indiquer dans le prédicat de ce que vous vouliez trouver - qui serait le mieux fait avec une arborescence d'expression... mais que serait une douleur à analyser. Fondamentalement, la signature de
First
n'est pas vraiment adapté pour une recherche binaire.Je vous suggère de ne pas essayer de surcharger le existant signatures, mais en écrire un nouveau, par exemple
(Je ne vais pas à la mettre en œuvre dès maintenant, mais je peux le faire plus tard si vous le souhaitez.)
En fournissant une fonction, vous pouvez effectuer une recherche par la propriété de la collection est classée par la, plutôt que par les éléments eux-mêmes.
Enumerable.First(predicate)
fonctionne sur unIEnumarable<T>
qui prend uniquement en charge de l'énumération, il n'a donc pas accès aléatoire pour les éléments à l'intérieur.Aussi, votre prédicat contient du code arbitraire qui aboutit à vrai ou faux, et ne peut donc pas indiquer si l'élément testé est trop faible ou trop élevée. Cette information serait nécessaire pour faire une recherche binaire.
Enumerable.First(predicate)
ne pouvez tester chaque élément dans l'ordre comme il se promène à travers l'énumération.Garder à l'esprit que tous les(? au moins la plupart) de l'extension des méthodes utilisées par LINQ sont mis en œuvre sur
IQueryable<T>
ouIEnumerable<T>
ouIOrderedEnumerable<T>
ouIOrderedQueryable<T>
.Aucun de ces interfaces prend en charge l'accès aléatoire, et, par conséquent, aucun d'entre eux peut être utilisé pour une recherche binaire. L'un des avantages de quelque chose comme LINQ, c'est que vous pouvez travailler avec de grands ensembles de données sans avoir à retourner l'ensemble du jeu de données à partir de la base de données. Évidemment, vous ne pouvez pas binaire de recherche quelque chose si vous n'avez même pas toutes les données encore.
Mais comme d'autres l'ont dit, il n'ya aucune raison vous ne pouvez pas écrire de cette méthode d'extension pour
IList<T>
ou d'autres types de collection qui prennent en charge l'accès aléatoire.