美文网首页
译:词频练习的Ruby实现

译:词频练习的Ruby实现

作者: 李小西033 | 来源:发表于2017-06-13 00:03 被阅读26次

Word Count Exercise in Ruby

题目

单词计数
编写程序来计算给定短语中每个单词出现的次数。
例如输入"olly olly in come free"
计数结果应为:
olly: 2
in: 1
come: 1
free: 1

简单吧,让我们来动手实现:

class Phrase
  attr_accessor :words
  def initialize(words)
    @words = words
  end

  def word_count
    word_list = {}
    words.split(" ").each do |word|
    word_list = process_word_in_list(word, word_list)
    end 
    word_list
  end

  private
  def process_word_in_list(word, word_list)
    return word_list if word.empty?
    word_list[word] ||= 0
    word_list[word] += 1
    word_list
  end
end

最初的这一版实现很直接。创建一个hash,当单词出现时,对其相关hash键的值进行计数。够简单咯。
但是这里有三个问题:

  • word_count方法不易读
  • process_word_in_list方法的实现相当丑陋
  • 还对特殊字符和标点符号进行了计数
    (接下来这个版本看起来更丑,但这只是一切变好之前的过渡)
class Phrase
  attr_accessor :words
  def initialize(words)
    @words = words
  end

  def word_count
    prep_words_for_counting()
    word_list = {}
    words.split(" ").each do |word|
      word_list = process_word_in_list(word, word_list)
    end
    word_list
  end

 private
 def process_word_in_list(word, word_list)
   word = parse_word(word)
   return word_list if word.empty?
   word_list[word] ||= 0
   word_list[word] += 1
   word_list
 end

 def prep_words_for_counting
   words.gsub!(",", " ")
 end

 def parse_word(word)
   word.gsub!(/[^a-zA-Z0-9]/, "")
   word.downcase!
   word
 end
end

哦天,这个实现太恶心了。找大神帮我review之后作出了如下改进:

  1. 创建有默认值的hash。Hash.new(0)创建了一个hash并且将0作为各个键的默认值。
    这就可以砍掉word_list[word] ||= 0这一行了。
  2. 我不需要在遍历中将每个单词使用downcase转为小写——直接对整个字符串转换更好。
  3. 使用魔幻的ruby字符串方法:scan

Scan遍历字符串来匹配模式(可能是正则或者字符串)。对于每一个匹配,生成的结果可能返回到数组或者被传递到块中。
如下示例:

a = "cruel world"
a.scan(/\w+/)        #=> ["cruel", "world"]
a.scan(/.../)        #=> ["cru", "el ", "wor"]

基于新的ruby知识,接下来是我下一版的实现

class Phrase
  attr_accessor :words
  def initialize(words)
    @words = words
  end

  def word_count
    word_list = Hash.new(0)
    words.downcase.scan(/\w+/) do |word|
      word_list[word] += 1
    end
    word_list
  end
end

现在清晰多咯!使用scan可以省去大量之前进行检查和模式匹配的代码。
为了离完美更近一步,我们可以再作出以下优化:

  • 分离word_count方法
    这一点确实有些苛求,但是为了让word_count方法中的words.downcase.scan(/\w+/)可以更有表现力。让我们试着将细节提取到块中怎么样?
    最终实现:
class Phrase
  attr_accessor :words
  def initialize(words)
    @words = words
  end

  def word_count
    list = Hash.new(0)
    each_word { |word| list[word] += 1 }
    list
  end

private
  def each_word
    words.downcase.scan(/\w+/) { |word| yield word }
  end
end

新的each_word方法更具有表现力:它清楚的告知了输出内容,同时将实现的细节小心封装为私有方法。
就这样,这个练习一开始困扰了我。但是在实现它的过程中,我见识到了scan的威力,另外,这也是一个很好的将复杂的方法移到Ruby块的例子。

更新

Twitter上有些大神建议我通过使用inject或者each_with_object来简化hash的创建。
他们给了我一个简单的原则:“如果只需要累加值(例如创建hash),使用each_with_object,如果需要改变对象,使用inject”。基于此原则,进一步简化实现如下:

class Phrase
  attr_accessor :words
  def initialize(words)
    @words = words
  end

  def word_count
    each_word.each_with_object(Hash.new(0)) { |word, hash| hash[word] += 1 }
  end

private
  def each_word
    words.downcase.scan(/\w+/)
  end
end

相关文章

  • 译:词频练习的Ruby实现

    Word Count Exercise in Ruby 题目 单词计数编写程序来计算给定短语中每个单词出现的次数。...

  • iOS-进阶整理14 - cocoaPods的使用

    一、安装cocoaPods cocoaPods是Ruby实现的,用它必须有Ruby环境 1.安装Ruby环境 打开...

  • 译:Ruby动态方法

    通常情况下,我们使用关键字def来定义方法。但是当有一系列方法具有相同的结构和逻辑时,继续这样做未免显得有些重复并...

  • Go for Ruby developers(译)

    原文 如果你是一个 Ruby 开发者, 并且想要开始使用 Go, 这篇文章可以帮助你入门. 在这篇文章里, 我们会...

  • Python实现词频统计

    《百年孤独》词频统计 学习更多?欢迎关注本人公众号:Python无忧

  • Go 实现词频统计

    功能 统计多个文件中英文单词出现的次数 按照词频从多到少排序输出 支持并发 实现 创建 file.txt 内容如下...

  • MapReduce实现词频统计

    一、MapReduce编程指导思想 MapReduce的开发一共有八个步骤其中map阶段分为2个步骤,shuffl...

  • OmniAuth-YOYOW插件和基于Homeland的YOYO

    一、实现Ruby语言的OmniAuth-YOYOW插件: OmniAuth是在Ruby中最主流的实现第三方登录方案...

  • python词频统计实例

    项目概述 通过两个Python文件实现一个简单的词频统计。 本工程共有4个文件: file01:要统计的词频文件。...

  • Hadoop String预备知识

    基础练习: 熟悉Hadoop streaming工作机制,用streaming机制进行词频统计,对Hadoop思想...

网友评论

      本文标题:译:词频练习的Ruby实现

      本文链接:https://www.haomeiwen.com/subject/lourqxtx.html