Random Sentence Generator in Ruby : How to randomly select values on specific key in hash?

前端 未结 2 423
渐次进展
渐次进展 2021-01-27 02:19

I\'m working on a Ruby verison of RSG and somehow stuck on the sentence generating process (...)

so I managed to implement all functions like read, convert to hash...,et

相关标签:
2条回答
  • 2021-01-27 03:19

    I assume they're looking for a recursive method, let's call it generate.

    def generate(key)
    

    Read the hash at the key and take one randomly using sample:

      words = @hash[key].sample
    

    Then, for each word, check to see if it's a <key>. If so, call generate on it, otherwise save it:

        if (word.start_with?("<") && word.end_with?(">"))
          generate(word)
        else
          @sentence << word
        end
    

    Putting it all together:

    @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(" ")
    

    Notice I used @-variables to make their scope reachable from within the method.

    Sample output: The big yellow flowers sigh grumpily tonight.

    0 讨论(0)
  • 2021-01-27 03:19

    Code

    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  
    

    Examples

    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"
    

    Explanation

    Firstly, mod_hash is constructed.

    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"]}
    

    Then the initial sentence is obtained.

    start_key = '<start>'
    sentence = mod_hash[start_key].sample
      #=> "The <object> <verb> tonight."
    

    We now simply replace each word in sentence that begins '<' and ends '>' with a randomly-selected element of the value of that key in mod_hash (the value being an array of strings). This continues until there are no more such words in sentence.

    The question mark in the regex means that one or more characters are to be matched lazily. That means that the match is terminated as soon as the first '>' is encountered. If, for example, the sentence were "a <hat> and <cat>!", the regex would match both <hat> and <cat>. By contrast, if the match were greedy (the default), it would match "<hat> and <cat>", which of course is not a key of mod_hash.

    Note that hash could have a structure that results in a non-terminating sequence of replacements.

    See Hash#transform_values.

    0 讨论(0)
提交回复
热议问题