En primer lugar me gustaría cambiar la forma ListControl
ve el origen de datos, que está convirtiendo resultado IEnumerable<string>
a List<string>
. Especialmente cuando acaba de escribir pocos caracteres, esto puede ser ineficaz (e innecesario). No haga copias extensivas de sus datos .
- Envolvería el
.Where()
resultado en una colección que implementa solo lo que se requiere de IList
(búsqueda). Esto le evitará crear una nueva lista grande para cada carácter que se escriba.
- Como alternativa, evitaría LINQ y escribiría algo más específico (y optimizado). Mantenga su lista en la memoria y cree una matriz de índices coincidentes, reutilice la matriz para no tener que reasignarla para cada búsqueda.
El segundo paso es no buscar en la lista grande cuando una pequeña es suficiente. Cuando el usuario comenzó a escribir "ab" y agrega "c", entonces no necesita buscar en la lista grande, la búsqueda en la lista filtrada es suficiente (y más rápida). Refinar busqueda cada vez que sea posible, no realice una búsqueda completa cada vez.
El tercer paso puede ser más difícil: mantenga los datos organizados para que se puedan buscar rápidamente . Ahora tienes que cambiar la estructura que usas para almacenar tus datos. imagina un árbol como este:
A B C
Agregue un mejor techo
Encima del contorno del hueso
Esto puede implementarse simplemente con una matriz (si está trabajando con nombres ANSI, de lo contrario, sería mejor un diccionario). Cree la lista de esta manera (con fines ilustrativos, coincide con el comienzo de la cadena):
var dictionary = new Dictionary<char, List<string>>();
foreach (var user in users)
{
char letter = user[0];
if (dictionary.Contains(letter))
dictionary[letter].Add(user);
else
{
var newList = new List<string>();
newList.Add(user);
dictionary.Add(letter, newList);
}
}
La búsqueda se realizará utilizando el primer carácter:
char letter = textBox_search.Text[0];
if (dictionary.Contains(letter))
{
listBox_choices.DataSource =
new MyListWrapper(dictionary[letter].Where(x => x.Contains(textBox_search.Text)));
}
Tenga en cuenta que utilicé MyListWrapper()
como se sugirió en el primer paso (pero omití la segunda sugerencia por brevedad, si elige el tamaño correcto para la clave del diccionario, puede mantener cada lista corta y rápida para, tal vez, evitar cualquier otra cosa). Además, tenga en cuenta que puede intentar utilizar los dos primeros caracteres para su diccionario (más listas y más corto). Si extiende esto, tendrá un árbol (pero no creo que tenga una cantidad tan grande de elementos).
Hay muchos algoritmos diferentes para la búsqueda de cadenas (con estructuras de datos relacionadas), solo por mencionar algunos:
- Búsqueda basada en autómatas de estado finito : en este enfoque, evitamos retroceder mediante la construcción de un autómata finito determinista (DFA) que reconoce la cadena de búsqueda almacenada. Estos son costosos de construir, por lo general se crean usando la construcción del conjunto de energía, pero son muy rápidos de usar.
- Stubs : Knuth – Morris – Pratt calcula un DFA que reconoce las entradas con la cadena a buscar como sufijo, Boyer – Moore comienza a buscar desde el final de la aguja, por lo que normalmente puede avanzar una longitud de aguja completa en cada paso. Baeza – Yates realiza un seguimiento de si los caracteres j anteriores eran un prefijo de la cadena de búsqueda y, por lo tanto, se adapta a la búsqueda de cadenas difusas. El algoritmo bitap es una aplicación del enfoque de Baeza-Yates.
- Métodos de índice : los algoritmos de búsqueda más rápidos se basan en el preprocesamiento del texto. Después de construir un índice de subcadena, por ejemplo, un árbol de sufijos o una matriz de sufijos, las ocurrencias de un patrón se pueden encontrar rápidamente.
- Otras variantes : algunos métodos de búsqueda, por ejemplo, la búsqueda de trigramas, están destinados a encontrar una puntuación de "cercanía" entre la cadena de búsqueda y el texto en lugar de una "coincidencia / no coincidencia". En ocasiones, se denominan búsquedas "difusas".
Pocas palabras sobre la búsqueda paralela. Es posible, pero rara vez es trivial porque la sobrecarga para hacerlo paralelo puede ser fácilmente mucho mayor que la búsqueda en sí. No realizaría la búsqueda en paralelo (la partición y la sincronización pronto se volverán demasiado expansivas y quizás complejas) pero movería la búsqueda a un hilo separado . Si el hilo principal no está ocupado, sus usuarios no sentirán ningún retraso mientras escriben (no notarán si la lista aparecerá después de 200 ms, pero se sentirán incómodos si tienen que esperar 50 ms después de escribir) . Por supuesto, la búsqueda en sí debe ser lo suficientemente rápida; en este caso, no utiliza subprocesos para acelerar la búsqueda sino para mantener la interfaz de usuario receptiva . consulta, no se bloqueará la interfaz de usuario, pero si su consulta fue lenta, seguirá siendo lenta en un hilo separado (además, también debe manejar múltiples solicitudes secuenciales).
HashSet<T>
no te ayudará aquí, porque estás buscando la parte de la cadena.