Word解析器脚本和实现memoization

时间:2016-01-09 19:19:49

标签: ruby dictionary memoization

描述

鉴于字典,我的程序会生成两个输出文件,' sequences.txt'和' words.txt'。

  • '序列'包含四个字母(A-z)的每个序列,它们恰好出现在字典的一个单词中,每行一个序列。
  • '也就是说'将包含包含序列的相应单词,顺序相同,每行一次。

例如,给定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 `<main>'

我已经阅读了Justin Weiss' article on memoization,并且大部分内容得到了它。只是很难将这种技术应用到我已经写过的东西中。

1 个答案:

答案 0 :(得分:1)

它不起作用,因为你从不调用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 || = ...表达式,这是我以前从未见过的。