Matriz de claves hash de PHP

Encontré esta clase de PHP simple en GitHub mientras buscaba filtros Bloom, esto se denominó "Filtro Bloom", pero creo que es más una "tabla hash". De cualquier manera, tengo curiosidad, es muy simple de entender.

Lee en un archivo de palabras y crea una clave Hash Array para cada palabra, luego puede verificar si la palabra existe en Hash Array.

Tengo curiosidad, sin embargo, ¿hay algún beneficio de usar esto en lugar de simplemente almacenar la palabra real como la clave o el valor de la matriz y luego verificar si esa palabra existe en la matriz? En teoría, esto solo sería agregar gastos generales y hacer lo mismo, por favor ayuda entiendo lo que me estoy perdiendo?

<?php
class Dictionary {
    private $words;
    private $wordsHash;
    public $hashLength;

    public function __construct($filepath, $hashLength) {
        $this->words = file($filepath);
        $this->hashLength = $hashLength;
        foreach($this->words as $word){
            $this->wordsHash[$this->createHash($word)] = true;
        }
        echo 'words: ' . count($this->words) . '   hashes: ' . count($this->wordsHash) . "\n";
    }

    public function createHash($str){
        $hash = substr(md5(trim($str)), 0, $this->hashLength);
        return $hash;
    }

    public function checkDictionary($str){
        $hash = $this->createHash(trim($str));
        if(array_key_exists ($hash , $this->wordsHash)){
            return true;
        }
        return false;
    }

}
?>

El archivo dictionary.txt tiene 10,000 palabras, solo mostraré algunas para la demostración

der
die
und
in
den
von
zu
das
mit
sich
des
auf
für
ist

Ejemplo de uso:

<?php
$dictionary = new Dictionary('dictionary.txt', 30);

if($dictionary->checkDictionary('den')){
    echo 'The Word den Exist in the Hash Table';
}else{
    echo 'The Word den DOES NOT Exist in the Hash Table';
}
?>

preguntado el 03 de mayo de 12 a las 21:05

Me parece que podrías hacer esto con matrices php normales que actúan como hashes:

@hackartist: Eso es lo que estaba pensando, pero pensé que debe haber una razón por la que alguien se tomó la molestia de hacer esto. -

4 Respuestas

La idea con esto parece ser que buscar una clave es mucho más rápido que buscar un valor específico en una matriz. Esto es especialmente cierto para arreglos muy grandes. Sin embargo, recomendaría un enfoque más simple para (como ya dijiste) evitar sobrecargas y colisiones:

$words = array_flip( file($filename) );

// The actual values are now the keys!
// So checking for a word works like this:
if (isset($words['und'])) {
    // ...

// Travling through the words works like this:
foreach ($words as $word => $i) {
    // ...

(PD: este código no funcionará como se esperaba, ya que cada palabra incluirá el salto de línea, por lo que primero deberá eliminarlo. Pero espero que capte la idea).

contestado el 03 de mayo de 12 a las 21:05

Este tipo de enfoque generalmente se realiza con cadenas muy grandes. Una vez usé este método al crear una galería. El archivo subido llevará el nombre del sha1 suma de comprobación de todo el archivo (mientras que el nombre real se guarda en una base de datos). De esta manera, si se carga un archivo duplicado, se negará fácilmente.

No sé exactamente qué beneficio obtendría al codificar cadenas de 3 letras (o incluso cadenas de 50 letras). Yo no lo haría de esa manera. Tendrás que preguntarle al desarrollador original.

contestado el 03 de mayo de 12 a las 21:05

Si lo encontró en github, probablemente valga la pena preguntarle al autor del código que encontró.

La clase de diccionario tiene 2 beneficios: recorta las teclas y evita los duplicados, pero el siguiente código es en su mayoría equivalente y es probable que sea mucho más rápido:

$words = file($filepath);
$words = array_map('trim', $words);
$words = array_unique($words);
sort($words); // just for convenience debugging

...

if (in_array($test, $words)) {
    return true;
} else {
    return false;
}

En caso de duda, la evaluación comparativa de cada (o cualquier) técnica de la competencia debe indicar claramente cuál es la mejor solución para un caso de uso determinado.

contestado el 03 de mayo de 12 a las 21:05

No veo ninguna diferencia funcional entre ese constructor y simplemente usar las palabras como claves. Las matrices en php con no numéricos son esencialmente hashmaps (en sintaxis y en implementación, si no recuerdo mal). Considere este fragmento:

$contents = file($filepath);
$dictionary = array();
foreach($contents as $word) {
    $dictionary[$word] = $word;
}

if(array_key_exists('den', $dictionary){
    echo 'The Word den Exist in the Hash Table';
}else{
    echo 'The Word den DOES NOT Exist in the Hash Table';
}

Hace lo mismo que la clase de muestra. Lo único que pierdes es el -> sintaxis, pero técnicamente podrías usar $dictionary['den'] como su condición existe... Devuelve nulo si no está configurado, lo que se evalúa como falso, entonces...

La clase también comete un no-no en informática al usar una función hash criptográfica donde no se requiere seguridad criptográfica. El algoritmo MD5 es mucho más costoso de ejecutar que una función hash regular, no segura (relativamente; llamar a MD5 seguro es dudoso en este momento). Usar la clase de diccionario sería significativamente más lento además de no proporcionar realmente nada. Como señala Truth, comparar resúmenes de cadenas muy largas puede ahorrarle tiempo. Pero calcular los resúmenes sigue siendo costoso y calcular resúmenes para cadenas de 3 letras no es más que una pérdida de tiempo.

contestado el 03 de mayo de 12 a las 21:05

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.