Word解析器脚本和实现memoization

描述

给定一个字典,我的程序生成两个输出文件,’sequences.txt’和’words.txt’。

  • ‘sequences’包含四个字母(Az)的每个序列,它们恰好出现在字典的一个单词中,每行一个序列。
  • ‘words’将包含包含序列的相应单词,顺序相同,每行一次。

例如,给定spec/fixtures/sample_words.txt字典仅包含

 arrows carrots give me 

产出应该是:

 'sequences' 'words' carr carrots give give rots carrots rows arrows rrot carrots rrow arrows 

当然,’arro’不会出现在输出中,因为它出现在多个单词中。

到目前为止我想出了什么

项目结构:

 ├── Gemfile ├── Gemfile.lock ├── examples │  └── dictionary.txt ├── lib │  └── word_sequence_parser.rb ├── main.rb ├── output ├── readme.md └── spec ├── fixtures │  └── sample_words.txt └── word_sequence_parser_spec.rb 

要运行脚本: ruby main.rb examples/dictionary.txt

main.rb的

 require_relative 'lib/word_sequence_parser.rb' dict_path = ARGV.shift if dict_path.nil? dict_path = 'spec/fixtures/sample_words.txt' end parser = WordSequenceParser.new(dict_path) # step 1 - Opens dictionary file and generates a new set of words parser.set # step 2 - Parses word sequences parser.sequence # step 3 - Prints to files in ./output parser.dump_text 

有效的脚本

word_sequence_parser.rb

 require 'set' class WordSequenceParser def initialize(path) @path = path end def set set = Set.new File.open(@path) do |f| f.each_line do |line| set.add(line.chomp.downcase) end end set end def sequence sequences = Set.new words = Set.new to_remove = Set.new set.each do |w| letters = w.split(//) letters.each_cons(4) do |seq| s = seq.join if !words.add?(s) to_remove.add(s) end sequences.add( {seq: s, word: w} ) end end sequences.delete_if { |hash| to_remove.include?(hash[:seq]) } end def dump_text output_s = File.open( 'output/sequences.txt', 'w' ) output_w = File.open( 'output/words.txt', 'w' ) sequence.each do |hash| output_s.puts("#{hash[:seq]}") output_w.puts("#{hash[:word]}") end output_s.close output_w.close end end 

我对脚本的镜头记忆不起作用

 require 'set' class WordSequenceParser def initialize(path) @path = path end def set set = Set.new File.open(@path) do |f| f.each_line do |line| set.add(line.chomp.downcase) end end set end def memoize @set = set end def sequence sequences = Set.new words = Set.new to_remove = Set.new @set.each do |w| letters = w.split(//) letters.each_cons(4) do |seq| s = seq.join if !words.add?(s) to_remove.add(s) end sequences.add( {seq: s, word: w} ) end end sequences.delete_if { |hash| to_remove.include?(hash[:seq]) } end def dump_text output_s = File.open( 'output/sequences.txt', 'w' ) output_w = File.open( 'output/words.txt', 'w' ) sequence.each do |hash| output_s.puts("#{hash[:seq]}") output_w.puts("#{hash[:word]}") end output_s.close output_w.close end end 

尝试运行脚本时收到此错误消息。

 ../word_sequence_parser.rb:29:in `sequence': undefined method `each' for nil:NilClass (NoMethodError) from main.rb:15:in `' 

我已经阅读了贾斯汀韦斯关于记忆的文章,并且大部分都得到了它。 只是很难将这种技术应用到我已经写过的东西中。

它不起作用,因为你从不调用memoize,所以@set永远不会被初始化。

然而,这里真正的问题是没有什么值得记住的。

您的原始代码看起来非常好,如果您考虑它如何工作的,那么任何代码都不会冗余执行 。 执行一次或多次执行的每一行都返回不同的值。

因此,记忆中没有任何目的。

让我们说你想多次调用dump_text(或只是序列)然后你肯定想要按如下方式记忆序列:

 def sequence @sequence ||= begin sequences = Set.new words = Set.new to_remove = Set.new set.each do |w| letters = w.split(//) letters.each_cons(4) do |seq| s = seq.join if !words.add?(s) to_remove.add(s) end sequences.add( {seq: s, word: w} ) end end sequences.delete_if { |hash| to_remove.include?(hash[:seq]) } end end 

这只会执行一次原始序列计算代码,然后分配@sequence。 对@sequence的每次其他调用都将重用已经计算过的@sequence的值(因为它现在不是nil。)

我喜欢这个问题,因为这是我公司开始使用ruby时的第一件事 。 我们有一个顾问重做了很多旧的asp.net代码,他在方法中有这些@foo || = …表达式,这是我以前从未见过的。