2011-08-23 14 views
14

Estoy queriendo escribir un anagrama tipo solucionador en Ruby pero va a funcionar contra una lista de palabras, como tal.Ruby anagram solver

Lista de palabras es:

the 
these 
one 
owner 

que permitiría al usuario que introduzca algunas letras, por ejemplo, NOE, y sería buscar en la lista de palabras para las palabras que se pueda hacer uso de las cartas que tiene el usuario de entrada y devolvería one y si ingresaban "eth" o incluso "the" devolvería the. He estado tratando de pensar en una forma eficiente de hacerlo, pero he estado recorriendo cada palabra, comparé una letra de la palabra, comprobando la palabra para cada letra y ambas longitudes coinciden. ¿Alguien puede dar consejos de una manera mejor y más eficiente de hacer esto?

Respuesta

30

La gran idea es que todos los anagramas son idénticos cuando ordenados. Entonces, si construyes un hash (no sé a qué Ruby llama esto) de listas, donde las claves son palabras ordenadas y el valor es la lista de palabras que ordena a la clave dada, entonces puedes encontrar anagramas muy rápidamente clasificando el palabra y buscar en su hash.

+1

Gran idea. ¿Qué tal el solucionador de anagramas de varias palabras? Me gusta 'rrenaud' =>' Ad Rerun'? –

+0

@KimmoLehpara dividir las oraciones en matrices y luego eliminar todas las instancias de carácter de espacio de las matrices. Después de eso, ordena las matrices y luego hazlas coincidir. –

2

no pude resistir la resolución de este cuestionario rubí :)

class String 

    def permutation(&block) 
    arr = split(//) 
    arr.permutation { |i| yield i.join } 
    end 
end 


wordlist = ["one", "two"] 

"noe".permutation do |i| 
    puts "match found: #{i}" if wordlist.include?(i) 
end 

La idea básica es que crea y utiliza matriz y que es función de permutación para subir con el resultado. Puede que no sea eficiente pero me parece elegante. : D respuesta

+0

oh mi, ¡me encanta! – thelastinuit

9

de rrenaud es grande, y aquí es un ejemplo de cómo construir un hash tal en rubí, dada una matriz denominada "words" que contiene todas las palabras en su diccionario:

@words_hash = words.each_with_object(Hash.new []) do |word, hash| 
    hash[word.chars.sort] += [word] 
end 

El código anterior asume ruby ​​1.9.2. Si está utilizando una versión anterior, entonces chars no existirá pero puede usar .split('').sort.

El objeto predeterminado del hash está configurado para ser el conjunto vacío, lo que hace que la codificación sea más fácil en algunos casos porque no tiene que preocuparse por el hash que le da cero.

Fuente: https://github.com/DavidEGrayson/anagram/blob/master/david.rb

+3

Eso es idéntico a 'words.group_by {| word | word.chars.sort} ' –

+0

Genial, pero en realidad tendrías que hacer esto:' @words_hash = words.group_by {| word | word.chars.sort}; @ words_hash.default = [] ' –

4

Una solución podría ser:

def combine_anagrams(words) 
    output_array = Array.new(0) 
    words.each do |w1| 
    temp_array = [] 
    words.each do |w2| 
     if (w2.downcase.split(//).sort == w1.downcase.split(//).sort) 
     temp_array.push(w2) 
     end 
    end 
    output_array.push(temp_array) 
    end 
    return output_array.uniq 
end 
0
def combine_anagrams(words) 
    cp = 0 
    hash = Hash.new [] 
    words.each do |word| 
    cp += 1 
    (cp..words.count).each do |i| 
     hash[word.to_s.chars.sort.join] += [word] 
    end 
    hash[word.to_s.chars.sort.join] = hash[word.to_s.chars.sort.join].uniq 
    end 
    return hash 
end 
0

Aquí es bastante similar mío. Lectura de un archivo de diccionario y comparación de caracteres clasificados como una matriz. La clasificación se realiza en candidatos preseleccionados.

def anagrams(n) 
    text = File.open('dict.txt').read 

    candidates = [] 
    text.each_line do |line| 
    if (line.length - 1) == n.length 
     candidates << line.gsub("\n",'') 
    end 
    end 

    result = [] 

    candidates.each do |word| 
    if word.chars.sort == n.chars.sort 
     result << word 
    end 
    end 

    result 

end