`
ijavagos
  • 浏览: 1242981 次
  • 性别: Icon_minigender_2
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

如何让Ruby代码更简练?!(原文最终修订于 2006-08-18 下午02:42:25)

阅读更多
你可以用它来做什么呢?请阅读...
我四前年曾接触过Ruby,就是为了看看这个语言到底什么样。我用了它一段时间然后就把注意力放到Fit,Fitness(译注1),和Java/.Net上了。然而最近,随着Rails的兴起,我又开始关注Ruby了;也开始认识到这是一个多么高效、亲和的语言。
学习一项事物最有效的还是通过实战学习。所以我决定从一个Ruby的Kata(译注2)开始,这样就可以反复去练习。我从Laurent Bossavit(译注3)的blog里挑出了哈利波特的Kata一篇。要解决这个问题中的某一块,就涉及到一种能产生一个集合的所有可能组合的算法。我在类库中寻找能做这种组合算法的模块,但只发现了一个做排列的家伙。所以我决定自己写一个。我觉得先写一个组合迭代器的测试会比较有趣。
这里就是使用rspec来写的测试:
require 'spec'
require 'Combinations'

context "Simple Combinations" do
specify "degenerate cases" do
Combinations.get(0,0).should.equal []
Combinations.get(1,0).should.equal []
Combinations.get(0,1).should.equal []
end

specify "nC1" do
Combinations.get(1,1).should.equal [[0]]
Combinations.get(2,1).should.equal [[0],[1]]
end

specify "nCn" do
Combinations.get(2,2).should.equal [[0,1]]
Combinations.get(3,3).should.equal [[0,1,2]]
end

specify "nCr" do
Combinations.get(3,2).should.equal [[0,1],[0,2],[1,2]]
Combinations.get(4,3).should.equal [[0,1,2],[0,1,3],[0,2,3],[1,2,3]]
Combinations.get(5,3).should.equal [
[0,1,2],[0,1,3],[0,1,4],[0,2,3],[0,2,4],[0,3,4],
[1,2,3],[1,2,4],[1,3,4],
[2,3,4]

]
end

end
而这里就是那些通过测试的组合模块:
class Combinations
  def self.c(n,r,&proc)
    if (n>0 && r>0)
      combine([], 0, n, r, proc)
    end
  end

  def self.get(n,r) 
    combinations = []
    Combinations.c(n,r) {|c| combinations << c}
    combinations
  end

  private
  def self.combine(combination, s, n, r, proc)
    if (r == 0)
      proc.call(combination)
    else
      (s..(n-r)).each {|i| combine(combination + [i], i+1, n, r-1, proc)}
    end
  end
end
我非常确定这个算法正确且有效。可是,我赫然发现一个稍早的版本固然精确,但效率却出奇的低。不同点在于:
(s...n).each {|i| combine(combination + [i], i+1, n, r-1, proc)}
令我烦心是,测试并没有发现这个效率低下的问题。我是在之后所做的一些手工的探索测试中才发现了这点。我想应该把它放在一个单元测试中来确保一个特定的最低效率值。不过我会把它放在另一篇blog中。
这篇blog的真正主题
是我不喜欢这个代码,它太不清晰了。可是到目前为止我还没找到一种让它更好的办法。我的目标是找到一种展现代码的方式,这样这个算法就能以明朗的面貌展现出来。我的这个算法太拥挤了,而且不能把自己描述清楚。(如何判断拥挤指数呢?就是让你完全理解它在做什么和为什么它能通过测试所花的时间的多少。)
有什么建议吗?
译者的话:因本文秉承Uncle Bob一贯的集思广益风格,属于一篇探讨性blog。原blog中有大量的专家讨论,译者特还其以原貌(请见以下评论内容),让大陆友人能够汲取更多相关知识。
----------------------------------------------------------------------------------------------------------
评论之一:
来自-> Matteo Vaccari
题目-> 清理组合代码
这些事情最好用递归定义的方式来解决。
让函数choose(n, k)来找出来自集合(0...n)的k个元素的所有不同组合。那么
choose(3, 0) == [[]]
choose(3, 1) == [[0], [1], [2]]
choose(3, 2) == [[0,1], [0,2], [1,2]]
等等。我们也有
choose(3, 4) == []
因为没办法从仅仅三个元素中找出4种元素的不同组合。
所以,让我们给choose(n, k)来写一个递归的定义;基本的情况是
choose(0, 0) == [[]]
choose(0, k) == [] if k > 0
这覆盖了所有n == 0 时的情况。现在让我们看看n==3,
choose(3, 1) == [[0], [1], [2]]
choose(3, 2) == [[0,1], [0,2], [1,2]]
那当n==4时会怎样呢?
choose(4, 2) == [[0,1], [0,2], [1,2], [0,3], [1,3], [2,3]]
酷!看起来前面一半和choose(3,2)一样
choose(4, 2) == choose(3, 2) + [[0,3], [1,3], [2,3]]
剩下的元素与choose(3,1)再加上新元素3是一样的
choose(4, 2) == choose(3, 2) + append_all(choose(3,1), 3)
这就说明这是一个普遍的规则。从一组(n+1)个元素元素中选出不同的k个元素的所有组合的方式是:
- 从一组n个元素中选出k个元素的所有组合,再加上
- k-1个旧元素的所有组合加上一个新的元素
测试优先!
def test_base
assert_equal [[]], choose(3, 0)
assert_equal [], choose(0, 3)
end
def test_step
# choose(1,1) == choose(0, 1) + append_all(choose(0, 0), 0)
# == [] + append_all([[]], 0)
# == [[0]]
assert_equal [[0]], choose(1, 1)
assert_equal [[0,1], [0,2], [1,2]], choose(3, 2)
assert_equal [[0,1], [0,2], [1,2], [0,3], [1,3], [2,3]], choose(4, 2)
assert_equal [[0,1,2,3]], choose(4, 4)
end
通过测试的代码是
def choose(n, k)
return [[]] if n == 0 && k == 0
return [] if n == 0 && k > 0
return [[]] if n > 0 && k == 0
new_element = n-1
choose(n-1, k) + append_all(choose(n-1, k-1), new_element)
end
def append_all(lists, element)
lists.map { |l| l << element }
end
既然我们递归调用k-1,我们必须增加一段代码去定义当k==0时的情况。这段代码当然是精简的。它也是清晰的,只要你明白了递归定义是如何
奏效的。
评论之二:
来自-> Dean Wampler
题目-> 一个更“美化”的调整?
这里是一个原始的rspec测试的调整,它试图用更美化的方式来封装Combinations.get()的调用,使用一个全局方法:
require 'spec'
require 'Combinations'
def get_combinations args
Combinations.get args[:for_n_items], args[:sets_of]
end
context "Simple Combinations" do
specify "degenerate cases" do
get_combinations(:sets_of => 0, :for_n_items => 0).should.equal []
get_combinations(:sets_of => 0, :for_n_items => 1).should.equal []
get_combinations(:sets_of => 1, :for_n_items => 0).should.equal []
end

specify "nC1" do
get_combinations(:sets_of => 1, :for_n_items => 1).should.equal [[0]]
get_combinations(:sets_of => 1, :for_n_items => 2).should.equal [[0],[1]]
end

specify "nCn" do
get_combinations(:sets_of => 2, :for_n_items => 2).should.equal [[0,1]]
get_combinations(:sets_of => 3, :for_n_items => 3).should.equal [[0,1,2]]
end

specify "nCr" do
get_combinations(:sets_of => 2, :for_n_items => 3).should.equal [[0,1],[0,2],[1,2]]
get_combinations(:sets_of => 3, :for_n_items => 4).should.equal [[0,1,2],[0,1,3],[0,2,3],[1,2,3]]
get_combinations(:sets_of => 3, :for_n_items => 5).should.equal [
[0,1,2],[0,1,3],[0,1,4],[0,2,3],[0,2,4],[0,3,4],
[1,2,3],[1,2,4],[1,3,4],
[2,3,4]

]
end
end
如果经常用的化会显得有些冗长,可是这对第一次使用的读者来说可以更容易读懂,而且也是个选择。
----------------------------------------------------------------------------------------------------------
译注:
1,Fit,Fitness,一个Object Mentor公司开发的关于验收性测试的知名框架,详情可访问http://fitnesse.org/
2,Kata,是目前北美和欧洲一些领先的软件咨询公司开创的一种用于掌握软件开发技能的手段,类似于国人乐谈的武功招式。目的就是试图寻找出软件开发中的一些招式,让学习者可以不断演练,从而打下一个良好的基础。
3,Laurent Bossavit,敏捷领域的一位知名专家,并有热门blog

Robert C. Martin的英文blog网址:http://www.butunclebob.com/ArticleS.UncleBob

译者注:Robert C. MartinObject Mentor公司总裁,面向对象设计、模式、UML、敏捷方法学和极限编程领域内的资深顾问。他不仅是Jolt获奖图书《敏捷软件开发:原则、模式与实践》(中文版)(《敏捷软件开发》(英文影印版))的作者,还是畅销书Designing Object-Oriented C++ Applications Using the Booch Method的作者。MartinPattern Languages of Program Design 3More C++ Gems的主编,并与James Newkirk合著了XP in Practice。他是国际程序员大会上著名的发言人,并在C++ Report杂志担任过4年的编辑。

分享到:
评论

相关推荐

    Ruby教程.简单教程docx

    ### Ruby教程知识点解析 #### 一、Ruby简介与特点 - **定义与历史**:Ruby是一种面向对象的脚本语言,由日本人松本行弘(Yukihiro Matsumoto)于1995年设计并发布。Ruby的设计哲学强调代码的可读性和简洁性,使得...

    ruby programming

    ### Ruby编程语言简介 #### 概述 Ruby是一种面向对象的、动态类型的脚本语言,由日本软件工程师松本行弘(Yukihiro Matsumoto)于1995年设计并开发。Ruby的设计理念是使编程变得简单、有趣且高效。它结合了Perl、...

    NetBeans Ruby and Rails IDE with JRuby 2009

    ### NetBeans Ruby and Rails IDE with JRuby 2009 #### 一、安装NetBeans IDE及Ruby支持 - **下载IDE**:首先需要下载最新版本的NetBeans IDE,该IDE集成了对Ruby的支持。 - **安装Java SDK**:由于NetBeans是...

    Ruby - Ruby for Rails

    根据提供的文件信息,我们可以将知识点大致分为以下几个部分...以上内容覆盖了 Ruby 和 Rails 的基础知识、核心概念和高级特性,对于初学者来说是非常宝贵的资源,能够帮助他们快速掌握这两种技术并应用于实际项目中。

    ruby-2.5.8.tar.gz

    Ruby是一种面向对象、动态类型的编程语言,由日本的松本行弘(Yukihiro Matsumoto)于1995年设计并开发。Ruby以其简洁、优雅的语法和强大的元编程能力而闻名,它强调程序员的生产力和代码的可读性。在Ruby-2.5.8版本中...

    Ruby编程Ruby Programming

    根据提供的文件信息,我们将深入探讨与“Ruby编程Ruby Programming”这一主题相关的几个核心知识点。这本面向初学者和高级读者的指南旨在全面介绍Ruby编程语言的基础及其高级特性,因此我们将从多个角度来解析这些...

    Ruby学习思维导图.pdf

    ### Ruby学习思维导图知识点详解 #### 一、基础知识 **1.1 变量与常量** - **局部变量**:以小写字母或下划线开头的变量,作用域仅限于定义它的方法或代码块。 - **全局变量**:以美元符号 `$` 开头的变量,在...

    Ruby语言教程.docx

    ### Ruby语言教程知识点详解 #### 一、Ruby语言概述与特点 - **基本概念**:Ruby是一种面向对象的动态编程语言,拥有简洁明了的语法结构。它支持多种编程范式,包括函数式编程和元编程。 - **应用场景**:广泛应用...

    Hello, Ruby World!

    ### Ruby语言概述 #### 一、Ruby语言简介 Ruby是一种高级、动态的面向对象编程语言,以其简洁且易于阅读的语法而闻名。它最初由日本人松本行弘(Yukihiro Matsumoto)于1995年设计并发布。Ruby的设计哲学之一是使...

    Head First Ruby 英语原版

    ### 关于《Head First Ruby...该书的教学方法注重实践和互动,有助于读者更快地掌握Ruby编程技能。无论是对于想要快速入门Ruby的新手还是希望进一步提高技能的开发者来说,《Head First Ruby》都是一本值得推荐的好书。

    Ruby on Rails Guides v2 - Ruby on Rails 4.2.5

    ### Ruby on Rails Guides v2 - Ruby on Rails 4.2.5 #### 一、重要概念及基础假设 - **重要概念**:本指南旨在帮助读者深入理解Ruby on Rails(以下简称Rails)4.2.5版本的核心功能与最佳实践。 - **基础假设**:...

    Ruby on Rail 基础知识 一张纸

    ### Ruby on Rails基础知识详解 #### 一、简介 在IT领域,Ruby on Rails(简称RoR或Rails)是一种流行的Web应用程序开发框架,基于Ruby语言。它遵循MVC(模型-视图-控制器)架构模式,使得开发高效且结构化。本篇文章旨在...

    红宝石之书:冒险的动手指南The Book Of Ruby: A Hands-On Guide for the Adventurous

    《红宝石之书:冒险的动手指南》作为一本详尽且免费的Ruby语言教程,为初学者和进阶用户提供了全面的学习资源。本书不仅涵盖了Ruby编程的基础知识,还深入探讨了高级主题,使得读者能够在实践过程中掌握Ruby的核心...

    ruby 程序设计

    ### Ruby 程序设计知识点概览 #### 一、Ruby语言概述 ##### §1.1 Ruby的历史 - **起源与发展**:Ruby是由日本程序员松本行弘(Yukihiro Matsumoto)于1995年开始开发的一种面向对象的脚本语言。它结合了Perl的...

    Ruby-ReekRuby代码味道探测器

    Ruby Reek 是一款强大的静态代码分析工具,专注于检测 Ruby 代码中的“坏味道”或不良编程习惯。这个工具可以帮助开发者提升代码质量,遵循更好的编程实践,从而使得代码更易于理解和维护。Reek 的核心理念是通过...

    基于Ruby语言的Ruby on Rails项目及其代码方案

    ### 基于Ruby语言的Ruby on Rails项目及其代码方案 #### 一、项目概述 本项目基于Ruby语言,利用Ruby on Rails(简称Rails)框架构建。Ruby on Rails是一款使用Ruby语言开发的应用程序框架,其核心是MVC(Model-...

    Ruby编程,实用程序员指南Programming Ruby, The Pragmatic Programmer's Guide

    《Ruby编程,实用程序员指南》是一本针对Ruby语言的学习教程与参考手册,旨在为程序员提供一个全面、深入的Ruby语言学习资源。本书不仅适合初学者快速入门,也适合具有一定经验的开发者进阶学习。 ### 一、Ruby语言...

Global site tag (gtag.js) - Google Analytics