Gerador de frases aleatórias em Ruby: como seleccionar aleatoriamente os valores da chave específica em hash?

Estou a trabalhar num Rubi verison da RSG e de alguma forma fiquei preso no processo de geração de frases...)

Então eu consegui implementar todas as funções como ler, converter para hash...,etc. Mas o problema é como escolher aleatoriamente valores em hash para gerar a sentença?

Agora tenho aqui um haxixe.
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
Author: Travis Su, 2017-10-31

2 answers

Presumo que estejam à procura de um método recursivo, digamos assim.
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.

 2
Author: Mark Thomas, 2017-10-31 00:13:04

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.

Ver Hash#transform_values.

 1
Author: Cary Swoveland, 2017-10-31 18:31:54