Gerador de frases aleatórias em Ruby: como seleccionar aleatoriamente os valores da chave específica em hash?
hash = {"<start>"=>[["The", "<object>", "<verb>", "tonight."]],
"<object>"=>[["waves"], ["big", "yellow", "flowers"], ["slugs"]],
"<verb>"=>[["sigh", "<adverb>"], ["portend", "like", "<object>"],["die", "<adverb>"]],
"<adverb>"=>[["warily"], ["grumpily"]]}
o objectivo é montar as cadeias de caracteres usando valores aleatórios no hash, por exemplo, quando a função itera para "<object>"
, irá tomá-la como uma chave e procurar no hash para encontrar a chave correspondente, em seguida, escolher aleatoriamente os valores correspondentes (uma das cadeias de caracteres em "<object>"=>[["waves"], ["big", "yellow", "flowers"], ["slugs"]]
) e montá-la, em seguida, o resultado seria algo como isto:
"The waves sigh warily tonight"
o meu código até agora:
hash.each do |_, value|
value.map{|x| x.map{|y| is_non_terminal?(y) ? (puts value.values_at("SomethingToPutInto")) : (puts y)}}
end
De alguma forma, a lógica do Código torna-se demasiado complicada e eu estou preso neste passo.. A utilização de values_at
irá causar erro de Impressão: no implicit conversion of String into Integer (TypeError)
Para is_non_terminal?(y)
é apenas uma função para verificar se o texto contém <
e >
:
def is_non_terminal?(s)
s.include?('<' && '>') ? true : false
end
2 answers
def generate(key)
Leia o hash na tecla e tome um aleatoriamente usando sample
:
words = @hash[key].sample
Então, para cada palavra, verifique se é um <key>
. Em caso afirmativo, chame generate
sobre ele, caso contrário guarde-o:
if (word.start_with?("<") && word.end_with?(">"))
generate(word)
else
@sentence << word
end
Juntando tudo:
@hash = {"<start>"=>[["The", "<object>", "<verb>", "tonight."]],
"<object>"=>[["waves"], ["big", "yellow", "flowers"], ["slugs"]],
"<verb>"=>[["sigh", "<adverb>"], ["portend", "like", "<object>"],["die", "<adverb>"]],
"<adverb>"=>[["warily"], ["grumpily"]]}
@sentence = []
def generate(key)
words = @hash[key].sample
words.each do |word|
if (word.start_with?("<") && word.end_with?(">"))
generate(word)
else
@sentence << word
end
end
end
generate("<start>")
puts @sentence.join(" ")
Repare que usei as @ - variáveis para tornar o seu âmbito Acessível a partir do método.
Resultado Da Amostra: The big yellow flowers sigh grumpily tonight.
Código
def generate(hash, start_key)
mod_hash = hash.transform_values{ |v| v.map { |a| a.join(' ') } }
sentence = mod_hash[start_key].sample
while sentence.include?('<')
sentence.gsub!(/\<.+?\>/) { |s| mod_hash[s].sample }
end
sentence
end
Exemplos
hash = { "<start>" =>[["The", "<object>", "<verb>", "tonight."]],
"<object>"=>[["waves"], ["big", "yellow", "flowers"], ["slugs"]],
"<verb>" =>[["sigh", "<adverb>"], ["portend", "like", "<object>"],
["die", "<adverb>"]],
"<adverb>"=>[["warily"], ["grumpily"]]}
generate(hash, '<start>') #=> "The big yellow flowers die grumpily tonight."
generate(hash, '<start>') #=> "The waves die warily tonight."
generate(hash, '<start>') #=> "The slugs sigh warily tonight."
generate(hash, '<verb>') #=> "portend like big yellow flowers"
Anotações
Em Primeiro Lugar, mod_hash
é construído.
mod_hash = hash.transform_values{ |v| v.map { |a| a.join(' ') } }
#=> {"<start>" =>["The <object> <verb> tonight."],
# "<object>"=>["waves", "big yellow flowers", "slugs"],
# "<verb>" =>["sigh <adverb>", "portend like <object>", "die <adverb>"],
# "<adverb>"=>["warily", "grumpily"]}
Então a frase inicial é obtida.
start_key = '<start>'
sentence = mod_hash[start_key].sample
#=> "The <object> <verb> tonight."
Nós agora simplesmente substituímos cada palavra em sentence
que começa '<'
e termina '>'
com um elemento aleatoriamente seleccionado do valor dessa chave em mod_hash
(o valor sendo um conjunto de cadeias de caracteres). Isto continua até que não haja mais tais palavras em sentence
.
A o ponto de interrogação na expressão regular significa que um ou mais caracteres devem ser correspondidos de forma preguiçosa . Isso significa que o jogo é terminado assim que o primeiro '>'
é encontrado. Se, por exemplo, a sentença fosse "a <hat> and <cat>!"
, a expressão regular corresponderia a <hat>
e <cat>
. Por outro lado, se o jogo fosse greedy (o padrão), ele iria corresponder "<hat> and <cat>"
, o que, claro, não é uma chave de mod_hash
.
Note que hash
pode ter uma estrutura que resulta numa sequência de não-terminação de substituicao.