Tengo 60k elementos que deben verificarse en una lista de búsqueda de 20k. ¿Hay un objeto de colección (como List
, HashTable
) que proporcione un Contains()
método excepcionalmente rápido ? ¿O tendré que escribir el mío? En otras palabras, es el Contains()
método predeterminado simplemente escanear cada elemento o utiliza un mejor algoritmo de búsqueda.
foreach (Record item in LargeCollection)
{
if (LookupCollection.Contains(item.Key))
{
// Do something
}
}
Nota . La lista de búsqueda ya está ordenada.
c#
.net
search
collections
Ondrej Janacek
fuente
fuente
Respuestas:
En el caso más general, considérelo
System.Collections.Generic.HashSet
como su estructura de datos de caballo de batalla "Contiene" predeterminada, porque lleva tiempo constante evaluarlaContains
.La respuesta real a "¿Cuál es la colección de búsqueda más rápida" depende del tamaño de datos específico, el orden, el costo del hash y la frecuencia de búsqueda.
fuente
Si no necesita hacer un pedido, intente
HashSet<Record>
(nuevo en .Net 3.5)Si lo hace, use un
List<Record>
y llameBinarySearch
.fuente
ImmutableSortedSet
de System.ImmutableCollections¿Lo has considerado
List.BinarySearch(item)
?¿Dijiste que tu gran colección ya está ordenada, así que esta parece ser la oportunidad perfecta? Un hash definitivamente sería el más rápido, pero esto trae sus propios problemas y requiere mucha más sobrecarga para el almacenamiento.
fuente
Debería leer este blog que probó la velocidad de varios tipos diferentes de colecciones y métodos para cada uno utilizando técnicas de subprocesos simples y múltiples.
De acuerdo con los resultados, una BinarySearch on a List y SortedList fueron los que tuvieron mejores resultados constantemente corriendo codo con codo al buscar algo como un "valor".
Cuando se usa una colección que permite "claves", Dictionary, ConcurrentDictionary, Hashset y HashTables obtuvieron el mejor rendimiento general.
fuente
Mantenga ambas listas x e y en orden ordenado.
Si x = y, realice su acción, si x <y, avance x, si y <x, avance y hasta que cualquiera de las listas esté vacía.
El tiempo de ejecución de esta intersección es proporcional a min (tamaño (x), tamaño (y))
No ejecute un bucle .Contains (), esto es proporcional a x * y que es mucho peor.
fuente
Si es posible ordenar sus elementos, entonces hay una manera mucho más rápida de hacer esto, luego hacer búsquedas clave en una tabla hash o b-tree. Sin embargo, si sus artículos no se pueden ordenar, realmente no puede ponerlos en un árbol b de todos modos.
De todos modos, si se pueden ordenar ambas listas, entonces solo es cuestión de recorrer la lista de búsqueda en orden.
fuente
Si está utilizando .Net 3.5, puede hacer un código más limpio usando:
No tengo .Net 3.5 aquí, por lo que no se ha probado. Se basa en un método de extensión. No
LookupCollection.Intersect(LargeCollection)
es probable que no sea lo mismo queLargeCollection.Intersect(LookupCollection)
... esto último es probablemente mucho más lento.Esto supone que LookupCollection es un
HashSet
fuente
Si no está preocupado por chirriar hasta el último bit de rendimiento, la sugerencia de usar un HashSet o una búsqueda binaria es sólida. Sus conjuntos de datos simplemente no son lo suficientemente grandes como para que esto sea un problema el 99% del tiempo.
Pero si esta es solo una de las miles de veces que va a hacer esto y el rendimiento es crítico (y se demuestra que es inaceptable usando HashSet / búsqueda binaria), ciertamente podría escribir su propio algoritmo que recorrió las listas ordenadas haciendo comparaciones a medida que avanzaba. Cada lista se recorrería como máximo una vez y en los casos patológicos no sería malo (una vez que haya seguido esta ruta, probablemente encontrará que la comparación, suponiendo que sea una cadena u otro valor no integral, sería el gasto real y esa optimización sería el siguiente paso).
fuente