Después de esta pregunta, sabemos que dos diccionarios diferentes, dict_1 y dict_2 por ejemplo, use exactamente la misma función hash.

¿Hay alguna forma de alterar la función hash utilizada por el diccionario? ¡También se aceptaron respuestas negativas!

4
gsamaras 8 may. 2016 a las 22:44

3 respuestas

La mejor respuesta

No puede cambiar la función hash: el dict llamará a hash en las teclas que se supone que debe insertar, y eso es todo.

Sin embargo, puede ajustar las claves para proporcionar diferentes __hash__ y __eq__ - Métodos.

class MyHash(object):
     def __init__(self, v):
         self._v = v

     def __hash__(self):
         return hash(self._v) * -1

     def __eq__(self, other):
         return self._v == other._v

Sin embargo, si esto realmente ayuda con su problema / pregunta original, dudo, parece que una estructura de datos personalizada basada en una matriz / lista podría ser la respuesta. O no.

3
deets 8 may. 2016 a las 20:30

Aquí hay una "tabla hash" en la parte superior de una lista de listas, donde cada objeto de la tabla hash está asociado con una función de hashing particular.

class HashTable(object):
    def __init__(self, hash_function, size=256):
        self.hash_function = hash_function
        self.buckets = [list() for i in range(size)]
        self.size = size

    def __getitem__(self, key):
        hash_value = self.hash_function(key) % self.size
        bucket = self.buckets[hash_value]
        for stored_key, stored_value in bucket:
            if stored_key == key:
                return stored_value
        raise KeyError(key)


    def __setitem__(self, key, value):
        hash_value = self.hash_function(key) % self.size
        bucket = self.buckets[hash_value]
        i = 0
        found = False
        for stored_key, stored_value in bucket:
            if stored_key == key:
                 found = True
                 break
            i += 1
        if found:
            bucket[i] = (key, value)
        else:
            bucket.append((key, value))

El resto de su aplicación aún puede ver la lista subyacente de cubos. Es posible que su aplicación requiera metadatos adicionales para asociar con cada depósito, pero eso sería tan simple como definir una nueva clase para los elementos de la lista de depósito en lugar de una lista simple.

2
mobiusklein 9 may. 2016 a las 14:31

Creo que lo que quieres es una forma de crear cubos . En base a esto, recomiendo collections.defaultdict con un inicializador set como el "depósito" (aunque depende de para qué lo estés usando).

Aquí hay una muestra:

#!/usr/bin/env python

from collections import defaultdict
from itertools import combinations

d = defaultdict(set)

strs = ["str", "abc", "rts"]
for s in strs:
    d[hash(s)].add(s)
    d[hash(''.join(reversed(s)))].add(s)

for combination in combinations(d.values(), r=2):
    matches = combination[0] & combination[1]
    if len(matches) > 1:
        print matches

# output: set(['str', 'rts'])

Dos cadenas que terminan en los mismos cubos aquí son muy probablemente iguales. He creado una colisión hash usando la función inversa y usando una cadena y es inversa como valores.

Tenga en cuenta que el conjunto usará una comparación completa, pero debería hacerlo muy rápido.

No mezcle demasiados valores sin agotar los conjuntos.

1
Reut Sharabani 8 may. 2016 a las 20:30