Fork me on GitHub

震惊小伙伴的单行函数式代码

几年前,函数式编程的复兴正值巅峰,一篇介绍 Scala 中 10 个单行函数式代码的博文在网上走红。很快地,一系列使用其他语言实现这些单行代码的文章也随之出现,比如HaskellRubyGroovyClojurePython,C#F#CoffeeScript

每篇文章都令人印象深刻的揭示了这些语言中一些出色优秀的编程特征。编程高手们利用这些技巧提高编程速度、改进软件质量,编程初学者能从这些简洁的预防中学到各种编程语言的真谛。本《震惊小伙伴的单行代码系列》将逐一介绍这些各种编程语言单行代码文章,供大家学习参考。

震惊小伙伴的单行代码●Erlang 篇

 

1. 让列表中的每个元素都乘以2

2. 求列表中的所有元素之和

3. 判断一个字符串中是否存在某些词

4. 读取文件

5. 祝你生日快乐!

6. 过滤列表中的数值

7. 获取 XML web service 数据并分析

8. 找到列表中最小或最大的一个数字

9. 并行处理

10. “Sieve of Eratosthenes”算法

震惊小伙伴的单行代码●CoffeeScript 篇

 

1. 让列表中的每个元素都乘以2

2. 求列表中的所有元素之和

(reduce == reduceLeft, reduceRight 也可以)

3. 判断一个字符串中是否存在某些词

下面的例子会返回匹配的单词:

~ is not a special operator in CoffeeScript, just a dirty trick. It is the bitwise NOT operator, which inverts the bits of it’s operand. In practice it equates to -x-1. Here it works on the basis that we want to check for an index greater than -1, and -(-1)-1 == 0 evaluates to false.

4. 读取文件

同步版本:

In node.js land this is only acceptable for application start-up routines. You should use the async version in your code.

5. 祝你生日快乐!

下面这一版读起来更像是伪代码:

6. 过滤列表中的数值

更函数式的方法:

7. 获取 XML web service 数据并分析

这里用 json 代替 XML:

8. 找到列表中最小或最大的一个数字

9. 并行处理

Not there yet. You can create child processes on your own and communicate with them, or use the WebWorkers API implementation. Skipping over.

10. “Sieve of Eratosthenes”算法

下面的代码可以写成一行吗?

跟紧凑的版本:

真正的一行实现:

震惊小伙伴的单行代码●F#篇

 

1. 让列表中的每个元素都乘以2

2. 求列表中的所有元素之和

3. 判断一个字符串中是否存在某些词

4. 读取文件

5. 祝你生日快乐!

6. 过滤列表中的数值

7. 获取 XML web service 数据并分析

8. 找到列表中最小或最大的一个数字

9. 并行处理

10. 素数

震惊小伙伴的单行代码●R语言篇

 

1. 让列表中的每个元素都乘以2

2. 求列表中的所有元素之和

3. 判断一个字符串中是否存在某些词

4. 读取文件

5. 祝你生日快乐!

6. 过滤列表中的数值

7. 获取 XML web service 数据并分析

8. 找到列表中最小或最大的一个数字

9. 并行处理

10. “Sieve of Eratosthenes”算法

震惊小伙伴的单行代码●Clojure 篇

1、让列表中的每个元素都乘以2

2、求列表中的所有元素之和

3、判断一个字符串中是否存在某些词

我这里使用了正则表达式,因为我觉得这是最优方法。

4、读取文件

Since Clojure Contrib has been deprecated for future Clojure releases, clojure.contrib.io/read-lines can be rewritten as (line-seq (clojure.java.io/reader (clojure.java.io/file “data.txt”))) in Clojure 1.3 onwards. Thanks to Aaron for pointing it out.

5、祝你生日快乐!

或者

6. 过滤列表中的数值

7. 获取 XML web service 数据并分析

8. 找到列表中最小或最大的一个数字

9. 并行处理

;; Assuming process-line to be a CPU intensive function that operates on a line (pmap process-line lines) ; Note the “p” in front of map

10. “Sieve of Eratosthenes”算法

I don’t I have a sufficiently good (in terms of performance & beauty) one line implementation of SoE. I would recommend checking out Christophe Grand’s treatise on the subject titled Everybody loves the Sieve of Eratosthenes for a great discussion on writing real world prime sieves in Clojure.

震惊小伙伴的单行代码●Haskell 篇

 

1、让列表中的每个元素都乘以2

2、求列表中的所有元素之和

3、判断一个字符串中是否存在某些词

4、读取文件

5、祝你生日快乐!

6. 过滤列表中的数值

7. 获取 XML web service 数据并分析

下面的例子需要使用 curl 和 xml 代码库,参考 RWH 里提供的安装方法。

8. 找到列表中最小或最大的一个数字

9. 并行处理

下面的例子需要使用 parallel 代码包。

10. 素数生成器

震惊小伙伴的单行代码●Groovy 篇

1、让列表中的每个元素都乘以2

2、求列表中的所有元素之和

3、判断一个字符串中是否存在某些词

4、读取文件

5、祝你生日快乐!

6. 过滤列表中的数值

7. 获取 XML web service 数据并分析

8. 找到列表中最小或最大的一个数字

9. 并行处理

Gpars 提供了直观安全的在 Groovy 里执行并行任务。

10. “Sieve of Eratosthenes”算法

震惊小伙伴的单行代码●Swift 篇

1、让列表中的每个元素都乘以2

2、求列表中的所有元素之和

3、判断一个字符串中是否存在某些词

4、读取文件

和其他语言不同,Swift 不能使用内建的函数读取文件,并把每一行存放到数组中。不过我们可以结合 split和 map方法写一段简短的代码,这样就无需使用 for循环:

最后一步使用 map函数和字符串的构造方法,将数组中的每个元素从字符数组(characters)转换为字符串。

5、祝你生日快乐!

6、过滤列表中的数值

假设我们需要使用一个给定的过滤函数将一个序列(sequence)分割为两部分。很多语言除了有常规的 map, flatMap, reduce, filter等函数外,还有一个 partitionBy函数恰好可以完成这个需求。正如你所知,Swift 没有类似的函数(我们不想在这里使用 NSArray中的函数,并通过 NSPredicate实现过滤功能)。

所以,我们可以通过拓展 SequenceType,并为它添加 partitionBy函数来解决这个问题。我们使用这个函数将整数数组分割为两部分:

实际上,这不是单行代码,而且使用了命令式的解法。能不能使用filter对它略作改进呢?

这种解法略好一些,但是他遍历了序列两次。而且为了用单行代码实现,我们删除了闭合函数,这会导致很多重复的内容(过滤函数和数组会在两处被用到)。

能不能只用单个数据流就对原来的序列进行转换,把两个部分分别存入一个元组中呢?答案是是可以的,使用 reduce方法:

这里我们创建了一个用于保存结果的元组,它包含两个部分。然后依次取出原来序列中的元素,根据过滤结果将它放到第一个或第二个部分中。

我们终于用真正的单行代码解决了这个问题。不过有一点需要注意,我们使用 append方法来构造两个部分的数组,所以这实际上比前两种实现慢一些。

7. 获取 XML web service 数据并分析

上述的某些语言不需要依赖外部的库,而且默认有不止一种方案可以处理 XML 格式的数据(比如 Scala 自身就可以将 XML 解析成对象,尽管实现方法比较笨拙),但是 (Swift 的)Foundation 库仅提供了 SAX 解析器,叫做 NSXMLParser。你也许已经猜到了:我们不打算使用这个。

在这种情况下,我们可以选择一些开源的库。这些库有的用 C 实现,有的用 Objective-C 实现,还有的是纯 Swift 实现。

这次,我们打算使用纯 Swift 实现的库: AEXML:

8. 找到列表中最小或最大的一个数字

9. 并行处理

某些语言支持用简单透明的方式允许对序列的并行处理,比如使用 mapflatMap这样的函数。这使用了底层的线程池,可以加速多个依次执行但又彼此独立的操作。

Swift 还不具备这样的特性,但我们可以用 GCD 实现:http://moreindirection.blogspot….llections-in-swift.html

10. “Sieve of Eratosthenes”算法

古老而优秀的埃拉托色尼选筛法被用于找到所有小于给定的上限 n 的质数。

首先将所有小于 n 的整数都放入一个序列(sequence)中,这个算法会移除每个数字的倍数,直到剩下的所有数字都是质数。为了加快执行速度,我们其实不必检查每一个数字的倍数,当检查到 n 的平方根时就可以停止。

基于以上定义,最初的实现可能是这样的:

在外层的区间里,我们遍历每一个需要检查的数字。对于每一个数字,我们使用 stride (through:Int by:Int)函数计算出由它的倍数构成的序列。最初,我们用所有 2 到 n 的整数构造了一个集合(Set),然后从集合中减掉每一个生成的序列中的元素。

不过正如你所见,为了真正的删除掉这些倍数,我们使用了一个外部的可变集合,这会带来副作用。

我们总是应该尝试消除副作用,所以我们先计算所有的子序列,然后调用flatMap方法将其中所有的元素展开,存放到单个数组中,最后再从原始的集合中删除这些整数。

这种写法更加清楚,它也是使用 flatMap展开嵌套数组这篇文章很好的一个例子。

震惊小伙伴的单行代码●C#篇

 

1、让列表中的每个元素都乘以2

2、求列表中的所有元素之和

3、判断一个字符串中是否存在某些词

4、读取文件

5、祝你生日快乐!

6. 过滤列表中的数值

7. 获取 XML web service 数据并分析

8. 找到列表中最小或最大的一个数字

9. 并行处理

10. “Sieve of Eratosthenes”算法

震惊小伙伴的单行代码●Python 篇

1、让列表中的每个元素都乘以2

2、求列表中的所有元素之和

3、判断一个字符串中是否存在某些词

4、读取文件

5、祝你生日快乐!

6. 过滤列表中的数值

7. 获取 XML web service 数据并分析

8. 找到列表中最小或最大的一个数字

9. 并行处理

10. “Sieve of Eratosthenes”算法

Python 里没有 Sieve of Eratosthenes 操作符,但这对于 Python 来说并不是难事。

震惊小伙伴的单行代码●Ruby 篇

 

1、让列表中的每个元素都乘以2

2、求列表中的所有元素之和

或者使用原生的 Symbol#to_proc 语法,这种语法出现在 Ruby 1.8.7:

或者直接传人 symbol:

3、判断一个字符串中是否存在某些词

4、读取文件

按数组读取时每行结尾字符都是 “\n” 换行符,你可以接着使用代码.map { str str.chop } 去掉它们,或者使用下面的替代方法:

5、祝你生日快乐!

6. 过滤列表中的数值

7. 获取 XML web service 数据并分析

这个例子里需要使用 open-uri 和 hpricot 代码库 (你也可以自己写一个)。代码不多,但 Scala 里的方法更优秀。

8. 找到列表中最小或最大的一个数字

9. 并行处理

这跟 Scala 语言不一样,Ruby 里的多核支持不是内置的。它需要使用parallel 或其它类似的 gem。

10. “Sieve of Eratosthenes”算法

Scala 语言里一行代码就能完成,但可读性不好,在 Ruby 里可以简单的实现,但不是一行代码:

这个例子直接拷贝自 StackOverflow。不是特别简洁,但你可以看明白。

震惊小伙伴的单行代码●Scala 篇

 

1. 让列表中的每个元素都乘以2

map函数能将列表中的每个元素依次取出,并用指定的函数依次处理每个元素。在下面的例子里,我们将依次取出每个列表元素,并将它们依次乘以2。这些操作执行完成之后,返回的列表包含的元素个数不变。这是跟reduceLeft和 foldLeft 等只返回一个值的函数的不同之处。

2. 求列表中的所有元素之和

reduceLeft函数最常用的功能是求列表里的所有元素之和。下面的例子里,我们使用range函数创建一个11000的列表,然后用reduceLeft遍历每个元素,相加求和。(附增用更简单的内置函数sum求和。)

3. 判断一个字符串中是否存在某些词

下面的例子中,如果字符串中包含列表中的某个单词,则返回真,否则假。我常使用这个技巧来检查一条微博里是否含有我感兴趣的词汇。从技术上将下面是三行代码,但前两行只能算作变量。

4. 读取文件

如果你是使用 Java 编程的程序员,这一行代码也许会让你惊讶,而在 Scala 里用一行代码就能读取和分析文件是很常见的事。下面是读取一个文件的两个例子,一个将整个文件读取都一个字符串里,另外一个读取文件并按行装入一个列表里。

5. 祝你生日快乐!

一行代码打印出“祝你生日快乐!”歌。下面的例子里展示了 Scala 的三元操作和 map 和 foreach 的混合使用。

6. 过滤列表中的数值

使用 partition 设定的条件将列表中的数字分为两类。下面的例子将学生按分数分为两个列表。

7. 获取 XML web service 数据并分析

因为 XML 是 Scala 中的一个原生结构,所有,分析 XML 是非常容易的。下面的例子是获取并分析 Twitter feed 的例子。

8. 找到列表中最小或最大的一个数字

下面的几个例子都使用了reduceLeft来遍历一个列表中的数据,并使用指定的函数分析它们。附增了使用更简单的 min/max 方法。

9. 并行处理

Scala 里有一个叫做”parallel collections”的集合类型,它能利用多核处理器来处理批量操作,例如foreachmapfilter, 等… 这里有一个视频可以参考。

下面的例子并不完整,但能很好的说明如何使用 parallel collections 并行处理。假设你有一堆数据在dataList里,有一个函数processItem来处理它们,但很耗 CPU。下面的这行代码就能让你使用并行技术处理你的数据。

10. “Sieve of Eratosthenes”算法

好吧,这个并不是很使用,技术上将不是一行,因为它使用了之前定义好的操作符,尽管不好阅读,但很强大。Daniel Sobral 发明了 Sieve of Eratosthenes 算法,可以用来判断一个数字是否是素数

需要使用预定义的>操作符,它是一个从 F# 语言里借来的语法。你可以参考 Steve Gilham 的博客里的例子。

转载至:博客园

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注