使用CoffeeScript来解决Project Euler中的编程问题

本 系列 文章将探讨 CoffeeScript,这是构建于 ">JavaScript 基础之上的一种全新编程语言,它提供了非常干净的语法。CoffeeScript 可编译为高效的 JavaScript。除了在 Web 浏览器中运行 JavaScript 之外,您还可以将它与服务器应用程序的 Node.js 等技术一起使用。在 第 1 部分 中,学习了如何设置 CoffeeScript 编译器,并使用它创建了随时可在浏览器或服务器中运行的代码。

在本文中,我们将通过解决 Project Euler 中的几个编程问题来探讨 CoffeeScript 语言。文中的示例将指导您使用 CoffeeScript 的函数、作用域、解析 (comprehension)、块语句、数组和一些面向对象的方面。

函数、作用域和解析

您要解决的第一个 Project Euler 问题就是第 6 题,这道题要求您计算前几个自然数的平方和,然后获得这些数字的和的平方,随后算出两者的差值。对于这道题,您将使用 CoffeeScript Read-Evaluate-Print-Loop (REPL)。清单 1展示了 REPL 会话的代码和对应输出。

清单 1. REPL 第 6 题

coffee> square = (x) -> x*x[Function]coffee> sum = (nums) -> nums.reduce (a,b) -> a+b[Function]coffee> diff = (nums) -> (square sum nums) - (sum nums.map square)[Function]coffee> diff [1..100]25164150

详解:

在 REPL 中,定义一个函数。(如 第 1 部分 所述,CoffeeScript 延续了 JavaScript 的函数式编程特色,摒弃了 JavaScript 中大多数类似于 C 语言的语法,因为这些语法加大了实现优雅的函数式编程的难度。)

清单 1 中的示例定义了一个名为 square 的函数,并声明它将获取一个参数,返回该参数自身与自身的乘积(即求其平方)。随后,REPL 告诉您已经定义了一个函数。

定义另外一个名为 sum 的函数,该函数也接受一个参数:一个数组。随后 sum 函数对该数组调用 reduce 方法。

reduce 方法并不是在 CoffeeScript 中新增的,而是 JavaScript 自有的一部分(在 JavaScript 1.8 中添加)。reduce 方法类似于 Python 中的 reduce 函数,或者 Haskell 或 Scala 中的 fold 函数。它获取一个函数,从左至右地遍历数组,将该函数应用于此前由 fold 返回的值和数组中的下一个值。CoffeeScript 紧凑的函数语法使得 reduce 更易于使用。在本例中,传递给 reduce 的函数是由 (a,b) -> a + b 指定的。这个函数将获取两个值,将两值相加,随后将数组中的所有元素相加。

创建一个名为 diff 的函数,该函数将获取一个数字数组,并计算两个子表达式,随后将其相减。第一个子表达式将数组传递给 sum 函数,随后获取结果,并将其传递给 square 函数。

CoffeeScript 允许您在很多情况下忽略圆括号,以避免产生混淆。举例来说,square sum nums 等同于 square(sum(nums))。第二个子表达式调用数组的 map 方法,这也是一个 JavaScript 1.8 方法,以另一个函数作为其输入。随后它会将该函数应用于数组的各成员,根据结果创建一个新数组。清单 1 中的示例使用 square 函数作为 map 的输入参数,为您提供一个使用输入数组元素的平方构成的数组。随后,只需将此传递给 sum 函数,即可获得平方和。

将恰当的数字数组传递到 diff 函数之中,使用作用域 [1..100] 来解答第 6 题。

这个作用域等同于全部由从 1 到 100(包括 1 和 100 在内)的数字构成的数组。如果您希望将 1 和 100 排除在外,那么可以使用 [1...100],使用三个圆点,而非两个。将此传递给 diff 函数即可给出第 6 题的解。

让我们回过头来看看 Project Euler 的第一题,这道题要求您算出 1000 以内可以被 3 或 5 整除的所有整数的和。您可能会认为,这是 Project Euler 中最简单的问题。可以使用函数和作用域来轻松解决此问题,就像解答第 6 题一样。不过,在使用 CoffeeScript 的解析特性时,您可以创建如 清单 2 所示的优雅的解决方案。

清单 2. 使用解析解决第 1 题

coffee> (n for n in [1..999] when n % 3 == 0 or n % 5 == 0).reduce (x,y) -> x+y 233168

仅通过一行代码便可解决问题是最好不过,CoffeeScript 简明的语法使之能够通过单行方式解决问题。清单 2 中的解决方案使用解析创建了是 3 或 5 的倍数的所有整数的列表。首先从作用域 [1..999] 开始生成,但仅使用可被 3 或 5 整除的值。随后使用另外一个 reduce 来求取这些值的和。REPL 将计算这一行代码的结果,并输出问题的解。

下一节将处理略微有些复杂的问题,进一步探讨 CoffeeScript。

时间: 2024-09-20 12:13:41

使用CoffeeScript来解决Project Euler中的编程问题的相关文章

用python解决project euler中的题目

寒假期间学习了python,现在基本上就能上手使用它来解决project euler里面的题目了,用python真的是没得说的,一个字"赞".在C++中需要用一大堆代码实现的算法,在python中,只需要那么短短几行.而且还有惊艳的运行速度.借用<可爱的python>里面的一句话:"人生苦短,我用python". [project euler 055] 求经过一系列规则不能得到回文数的数的个数.题目在此: If we take 47, reverse a

解决在ASP中执行数据库查询中的特殊字符的问题

解决在ASP中执行数据库查询中的特殊字符的问题 在进行数据库的查询时,会经常遇到这样的情况: 例如想在一个用户数据库中查询他的用户名和他的密码,但恰好该用户使用的名字和密码中有特殊的字符,例如单引号,"|"号 双引号或者连字符"&". 例如他的名字是1'test,密码是A|&900 这时当你执行以下的查询语句时,肯定会报错: SQL = "SELECT * FROM SecurityLevel WHERE UID='" &

怎样解决右键菜单中没有word2013

  解决右键菜单中没有word2013的步骤如下: 步骤一:点击"开始"---"所有程序"---"附件"---"运行" 步骤二:在对话框中输入regedit 步骤三:然后后点"确定"进入注册表编辑器. 步骤四:点开第一个文件夹. 步骤五:在空白处用左键点一下,然后滚动鼠标滚动轮找到.docx为后缀的文件夹,点一下文件夹. 步骤六:双击右边名称下面对应的(默认)选项,弹出对话框. 步骤七:把数值数据中的(默认

用驱动人生如何解决设备管理器中的问题符号

  设备管理器中的问题符号的含义以及解决方法: 1.设备管理其中的红色的叉号 当"IEEE 1394总线主控制器"和"PCMCIA卡"中的硬件设备显示了红色的叉号,这说明该设备已被停用,事实上这是由于该笔记本电脑并不经常使用1394设备和PCMCIA卡,从节省系统资源和提高启动速度方面考虑,才禁用了这些设备. 解决办法:右键点击该设备,从快捷菜单中选择"启用"命令就可以了. 2.设备管理其中的黄色的问号或感叹号 如果看到某个设备前显示了黄色的问号

ios-找ipad开发高手,解决外接键盘中文选词被挡住的问题

问题描述 找ipad开发高手,解决外接键盘中文选词被挡住的问题 ipad2上开发的一个应用,发现外接蓝牙键盘在用中输入法时,选词会被编辑框挡住,有能解决的联系我,谢谢

【已解决】VirtualBox中的Ubuntu没有权限访问共享文件夹sf_win7_to_ubuntuw

[问题]  原文http://www.crifan.com/virtualbox_ubuntu_12_10_13_04_share_folder_with_win7_fail/ 之前已经搞定可以自动共享文件夹了: [已解决]Win7中无法和VirtualBox中的Ubuntu 13.04共享文件夹 但是现在发现无法去访问,没有权限: 即使是: 1 2 3 crifan@crifan-Ubuntu:~$sudochown-R crifan/media/sf_win7_to_ubuntu/ crif

帮用户解决以往消费中的例如信息不透明、使用不便捷、无法按照服务质量付费等痛点(转)

在所有还算得上成功的互联网公司中,大众点评一直是一个异类. 它既不会像其它公司那样像坠落凡间的天使,只需要短短几年的修复,迅速克隆一个"美国公司",就立马可以腾云驾雾,再次回到天堂:也不像那些泯然众人的公司那样,似乎永远不在舆论的中心,但一直默默在赚钱,只是在某一个瞬间,纳斯达克的钟声将人们唤醒,"哦,原来它这么厉害"! O2O 2.0 的演变 7 月 22 日,久不露面的大众点评 CEO 张涛出现在了成立丽人事业部的发布会上,除了为其新拓展的丽人事业部站台之外,张

安卓 布局 xml 引用-急用!请问,如何解决在tabhost中每个按钮下添加子页面?

问题描述 急用!请问,如何解决在tabhost中每个按钮下添加子页面? 子页面可以加载进入,但是子页面里面的响应事件点击没有反应.而且,如果子页面里面再引用其他页面,里面的内容也显示不出来. 解决方案 http://bbs.csdn.net/topics/380075344 解决方案二: http://blog.csdn.net/harvic880925/article/details/17120325 解决方案三: Tabspec tab1tab1.setIntent() 解决方案四: Tab

新手-代码本是用来解决在一个链表中插入一个元素,但是运行后结果总是与本意不同。亲们帮帮忙,看看怎么错了。

问题描述 代码本是用来解决在一个链表中插入一个元素,但是运行后结果总是与本意不同.亲们帮帮忙,看看怎么错了. #include using namespace std; struct List //定义一个结构体表示线性表 { int num; struct List *next; }; int main() { List la,*p,*head,*p1,*pm; //定义线性表la //把表a的首元素地址赋给p和head int n=1,m,t; cout<<"请输入表a中的第&q