Los fundamentos señalados por Marc y Jon son no está mal, pero están lejos de ser óptimos en términos de su distribución equitativa de los resultados. Lamentablemente, el enfoque de "multiplicar por primos" copiado por tanta gente de Knuth es not the best choice in many cases, se puede lograr una mejor distribución con funciones de cálculo más económicas (aunque esto es muy leve en hardware moderno). De hecho, lanzar primos en muchos aspectos de hash es no panacea.
Si esta información se utiliza para tablas hash de gran tamaño, recomiendo leer Bret Mulvey's excellent study and explanation of various modern (and not so modern) hashing techniques, hecho a mano con C#.
Tenga en cuenta que el comportamiento con cadenas de varias funciones hash es muy sesgado hacia wehther las cadenas son cortas (aproximadamente la cantidad de caracteres hashed antes de que los bits comiencen a fluir) o de largo.
Uno de los más simples y fáciles de implementar es también uno de los mejores, el hash de Jenkins One to time.
private static unsafe void Hash(byte* d, int len, ref uint h)
{
for (int i = 0; i < len; i++)
{
h += d[i];
h += (h << 10);
h ^= (h >> 6);
}
}
public unsafe static void Hash(ref uint h, string s)
{
fixed (char* c = s)
{
byte* b = (byte*)(void*)c;
Hash(b, s.Length * 2, ref h);
}
}
public unsafe static int Avalanche(uint h)
{
h += (h<< 3);
h ^= (h>> 11);
h += (h<< 15);
return *((int*)(void*)&h);
}
a continuación, puede utilizar este modo:
uint h = 0;
foreach(string item in collection)
{
Hash(ref h, item);
}
return Avalanche(h);
se puede combinar varios tipos diferentes de este modo:
public unsafe static void Hash(ref uint h, int data)
{
byte* d = (byte*)(void*)&data;
AddToHash(d, sizeof(int), ref h);
}
public unsafe static void Hash(ref uint h, long data)
{
byte* d= (byte*)(void*)&data;
Hash(d, sizeof(long), ref h);
}
Si sólo tiene acceso al campo como un objeto con sin conocimiento de los aspectos internos, simplemente puede llamar a GetHashCode() en cada uno y combinar ese valor de la siguiente manera:
uint h = 0;
foreach(var item in collection)
{
Hash(ref h, item.GetHashCode());
}
return Avalanche(h);
Lamentablemente no se puede hacer sizeof (T) por lo que debe hacer cada estructura de forma individual.
Si desea usar la reflexión, puede construir una función por tipo que haga identidad estructural y hash en todos los campos.
Si desea evitar un código inseguro, puede utilizar técnicas de enmascaramiento de bits para extraer bits individuales de las entradas (y caracteres si se trata de cadenas) sin demasiada molestia adicional.
Suena por su actualización que espera que la salida de este proceso tenga una probabilidad de colisión lo suficientemente baja como para tratarla como una clave única ... Necesita un hash muy bueno y bastantes bits más de 32 para que esto funcione – ShuggyCoUk
Si quieres una clave, usar un hash criptográfico normalmente será suficiente (siempre y cuando no te preocupen sus propiedades de cifrado MD5 está bien) pero será mucho más costoso de calcular que otras lo mismo que los hashes efectivos sin cifrado. – ShuggyCoUk