Python中的List表达式

一个小故事 三年前,我在一篇博客里不无自豪的记录了python编写的小函数,当时感觉python真强大,11行代码就写出了一个配置文件的解析器。 def loadUserInfo(fileName): userinfo = {} file = open(fileName, "r") while file: line = file.readline() if len(line) == 0: break if line.startswith('#'): continue key, value = line.split("=") userinfo[key.strip()] = value.strip() return userinfo 最近正在跟同事学习python在数据挖掘中的应用,又专门学习了一下python本身,然后用list comprehension简化了以下上面的代码: def loadUserInfo(file): return dict([line.strip().split("=") for line in open(file, "r") if len(line) > 0 and not line.startswith("#")]) 这个函数和上面的函数的功能一样,都是读取一个指定的key=value格式的文件,然后构建出来一个映射(当然,在Python中叫做字典)对象,该函数还会跳过空行和#开头的行。 比如,我想要查看一下.wgetrc配置文件: if __name__ == "__main__": print(loadUserInfo("/Users/jtqiu/.wgetrc")) 假设我的.wgetrc文件配置如下: http-proxy=10.18.0.254:3128 ftp-proxy=10.18.0.254:3128 #http_proxy=10.1.1.28:3128 use_proxy=yes 则上面的函数会产生这样的输出: {'use_proxy': 'yes', 'ftp-proxy': '10.18.0.254:3128', 'http-proxy': '10.18.0.254:3128'} list comprehension(列表推导式) 在python中,list comprehension(或译为列表推导式)可以很容易的从一个列表生成另外一个列表,从而完成诸如map, filter等的动作,比如:...

March 30, 2015 2 min

underscore中的集合操作

underscore.js中的集合操作 书接前文,我们在上一篇中将一个文本划分成了单词的数组,并统计了每个单词出现的频率。现在我们需要将排行前10的单词找出来。那么第一步就是将所有单词按照频率排序,然后将这个集合的前10个拿出来。 underscore.js为集合提供了丰富的API,这与函数式编程的鼻祖LISP语言有着直接的继承关系。LISP围绕着List提供了的众多函数。 排序 var contacts = [ { "name": "Juntao", "age": 29 }, { "name": "Abruzzi", "age": 30 }, { "name": "Sara", "age": 29 } ]; 比如想要将上面这个集合按照age排序,可以使用sortBy函数: var sorted = _(contacts).sortBy("age"); 默认的sortBy的返回值是按照升序排列的,不过JavaScript的数组原生就有reverse的API用以翻转数组,因此如果要得到降序的排列,只需要: var sorted = _(contacts).sortBy("age").reverse(); 抽取 有时候,我们需要从众多的信息中抽取自己关心的,比如上例中的contacts集合,我们在界面上仅仅需要name属性组成的集合,这时候可以通过pluck来完成抽取: var names = _.pluck(contacts, "name"); //["juntao", "abruzzi", "sara"] underscore.js默认的pluck只能抽取一层,如果遇到下面这种场景: var contacts = [ { "name": "Juntao", "age": 29, "address": { "street": "Dengling Rd" } }, { "name": "Sara", "age": 29, "address": { "street": "Zhangba 4th Rd" } } ] 想要抽取address....

February 21, 2015 3 min

略论函数式编程

JavaScript中的map/reduce 在过去的10年间,不论你是否对大数据有所涉足,你肯定听过map/reduce这个貌似很高大上的词。这个高大上的词事实上来自于函数式编程世界。map的意思是影射,即将一个集合中的内容,通过应用某种函数,形成另外一个集合。reduce表示求和,或者规约,即将一个集合以某种函数规约为一个值。 underscore.js是一个非常强大的JavaScript库,也是我的工具箱里的必备品。事实上在我自己的小项目中,我更倾向于使用jQuery+underscore.js来完成所有的功能,而不是使用诸如AngularJS之类的框架。 作为一个库,underscore.js提供了丰富的API来操作JavaScript中的集合,对象,函数等,可以节省程序员大量的时间,我们在这篇文章中来看看underscore.js中基本的函数式编程特性。 使用map消除for-loop 我们先来看一个小例子:我们要编写一个名为makeQuery的函数,它接受一个JavaScript对象和一个分隔符,然后将JavaScript对象展开,形成key=value[分隔符key=value]的形式。正如下面这个测试所反映的: it("make query from object", function() { var cookies = { "JSESSIONID": "6C729E682C05AA56017E3D1675CE8E5F", "_USER": "GEO-NASTAR" }; var expected = "JSESSIONID=6C729E682C05AA56017E3D1675CE8E5F;_USER=GEO-NASTAR"; expect(makeQuery(cookies, ";")).toEqual(expected); }); 一个直接的解决方案是: function makeQuery(obj, delimiter) { var strArray = []; for (var key in obj) { strArray.push(key + "=" + obj[key]); } return strArray.join(delimiter); } 我们再来看另外一个小例子:给定一个字符串(人名)数组,将数组中的所有人名都变成大写字母开头。正如下面这个测试所反映: it("capitalize", function() { var names = ["juanchen", "mingliang", "lu", "juntao"]; var expected = ["Juanchen", "Mingliang", "Lu", "Juntao"]; expect(capitalize(names))....

February 20, 2015 3 min

Common Lisp中的宏

Lisp与其他语言之区别 函数式编程,前缀表达式,繁多的括号,奇怪的操作符等等,这些都足以让Lisp和其他编程语言看起来有很大的区别,但是这些区别并非本质上的差异。让Lisp和其他编程语言有本质区别的是它对宏的支持。 C语言中的,被称为宏的预编译系统自有其好处,但是和Lisp中的宏比起来,好比的Notepad和Vim或者Emacs之间的差异。 数据与代码 在Lisp中,数据和代码间的差异非常小,上一篇文章简单讨论了引用的基本概念,其中对数据与代码的差异已经有所涉及。 宏(Macro) 简而言之,宏即替换,在Lisp中,可以通过程序生成代码(s-expr),而这些代码又可以被执行(当然,需要是合法的s-expr)。这一点赋予了宏无限的可能性,比如定义一个新的语法: (defmacro only (condition &rest body) `(if ,condition (progn ,@body))) Lisp中函数macroexpand-1可以用来查看调用时宏是如何展开的: > (macroexpand-1 '(only (> x 10) (format t "big than 10"))) (IF (> X 10) (PROGN (FORMAT T "big than 10"))) 上例中,(> x 10)被作为condition,而(format t "big than 10")作为body传递给了宏。 > (macroexpand-1 '(only (> x 10) (format t "big than 10") (format t "~%"))) (IF (> X 10) (PROGN (FORMAT T "big than 10") (FORMAT T "~%"))) 使用progn是为了让剩余的多条语句(如果有的话),逐条执行,并返回最后一条语句的值(正如在函数中那样)。...

June 15, 2013 2 min

Common Lisp基础

###Common Lisp 之前一直说JavaScript是一门被误解很深的语言,现在学习了一段时间Lisp后发现,Lisp才是!Lisp一直为人所诟病的是它虽然很强大,但是有点学院派,难当大用。但是读了七,八章《Practical Common Lisp》和几章《ANSI Common Lisp》之后发现,怎么就学院派了,其他编程语言能处理的,Lisp一样可以处理,其他语言处理不了的(或者很繁琐的,比如java中的循环,map之类),Lisp却能处理。 Lisp本质上是一个抽象语法树(AST)而已,但是又提供了一些操作这个AST的方法(比如强大的宏),这样很容易用Lisp开发出来一个新的DSL。用函数式编程的好处之一就是在编写完一个应用程序之后,通常还可以获得一个新的语言(于业务领域很匹配的语言)。 Common Lisp本身是Lisp的一个方言,是有一个标准来定义,其目的是为了标准化众多的Lisp分支而定。 sbcl环境 上一篇文章已经介绍了如何在Mac下配置Common Lisp的开发环境: 引用(quote) 由于在Lisp中,数据和代码都是通过S-expr来表示,所以需要用一种标记法来告诉解释器:这个表达式表示数据/代码。这就是引用的作用: > (+ 1 2 3 4 5) 15 > '(+ 1 2 3 4 5) (+ 1 2 3 4 5) 解释器会将s-expr的第一项作为函数(car),而将后续的元素(cdr)作为参数传递给第一项来调用,并求值。可以通过引用(quote)来阻止解释器这样解释。 反引号(`) 与引用对应的,有一个反引号形式的引用(在键盘上1的左边)。一般的用法上,它与quote的含义一样,都是防止解释器解释被引用的列表。 >`(a b c) (a b c) >`(a b (+ 1 2)) (a b (+ 1 2)) 但是,反引号引用的列表提供了重新启动求值的能力,这……,我的意思是,如上式中,如果想要将(+1 2)这个子列表求值,怎么做到呢?反引号引用提供了这个能力,用逗号(,)作为子列表的前缀即可: >`(a b ,(+ 1 2)) (a b 3) 这个当然在此刻看起来毫无用处,或者感觉略有画蛇添足之嫌,但是在宏中,这个操作符却有很广泛的用途,这里有一个有意思的例子: (defun foo (x) (only (> x 10) (format t "big than 10"))) 我们可以通过if来实现此处的only,当only之后的条件满足的话,就执行后续的所有语句:...

June 13, 2013 1 min