Una posible función hash podría ser (suponiendo solo palabras en inglés) un recuento ordenado del número de apariciones de cada letra. Entonces para "anagrama" generaría [('a', 3), ('g', 1), ('n', 1), ('m', 1), ('r', 1)].
Alternativamente, podría obtener una agrupación inexacta generando una máscara de bits de su palabra donde para los bits 0-25 cada bit representara la presencia o ausencia de esa letra (bit 0 representando 'a' hasta el bit 25 representando 'z') . Pero luego tendrías que hacer un poco más de procesamiento para dividir cada grupo hash aún más para distinguir, p. "a" de "demasiado".
¿Alguna de estas ideas ayuda? ¿Algún lenguaje de implementación particular en mente (podría hacer C++, python o Scala)?
Editar: se ha añadido algún ejemplo de código Scala y de salida:
OK: Estoy en el modo de Scala en el momento, así que he toqué algo que ver con lo que pides, pero (ejem) se puede no ser muy claro si no está familiarizado con Scala o la programación funcional.
El uso de una gran lista de palabras en inglés desde aquí: http://scrapmaker.com/data/wordlists/twelve-dicts/2of12.txt
corro el código Scala en ellos (tarda unos 5 segundos utilizando Scala 2.9 en el modo de escritura, incluyendo el tiempo para compilar, con un diccionario de alrededor de 40.000 palabras . No es el código más eficiente, pero lo primero que se me viene a la mente).
// Hashing function to go from a word to a sorted list of letter counts
def toHash(b:String) = b.groupBy(x=>x).map(v => (v._1, v._2.size)).toList.sortWith(_._1 < _._1)
// Read all words from file, one word per line
val lines = scala.io.Source.fromFile("2of12.txt").getLines
// Go from list of words to list of (hashed word, word)
val hashed = lines.map(l => (toHash(l), l)).toList
// Group all the words by hash (hence group all anagrams together)
val grouped = hashed.groupBy(x => x._1).map(els => (els._1, els._2.map(_._2)))
// Sort the resultant anagram sets so the largest come first
val sorted = grouped.toList.sortWith(_._2.size > _._2.size)
for (set <- sorted.slice(0, 10))
{
println(set._2)
}
Este vuelca a cabo los primeros 10 juegos de anagramas (conjuntos con la primera mayoría de los miembros) ser:
List(caret, cater, crate, react, trace)
List(reins, resin, rinse, risen, siren)
List(luster, result, rustle, sutler, ulster)
List(astir, sitar, stair, stria, tarsi)
List(latrine, ratline, reliant, retinal)
List(caper, crape, pacer, recap)
List(merit, miter, remit, timer)
List(notes, onset, steno, stone)
List(lair, liar, lira, rail)
List(drawer, redraw, reward, warder)
Tenga en cuenta que este utiliza la primera sugerencia (lista de cargos de letras) no el método de máscara de bits más complicado.
Edición 2: Se puede reemplazar la función hash con un mecanismo simple de los caracteres de cada palabra (como lo sugiere JAB) y obtener el mismo resultado con más claro/código más rápido:
def toHash(b:String) = b.toList.sortWith(_<_)
pregunta no terriblemente clara. ¿Puedes por favor reformular el objetivo? –
¿Quiere decir: Tengo un diccionario de un millón de palabras, deseo identificar todos los conjuntos de palabras dentro del diccionario que son anagramas el uno del otro? P.ej. Si el diccionario contiene: [tap, pat, pot, top], desearía ver [[tap, pat], [pot, top]]? –
Sí, @Alex. ¿Solo quiero cuántos anagramas diferentes hay? – vijay