关于列表推导式

列表推导式最开始是一些函数式编译语言的句法特征,比如模式匹配,它能极大提高函数式程序的读写能力。最开始并没有列表推导式,只有集合推导式(Set Comprehensions),列表推导式第一次使用是Turner1982年在KRC(Kent Recursive Calculator)上。列表推导式曾经在各种函数式编程语言中出现,如Miranda(一种纯粹的函数式编程语言),Orwell(一种lazy函数式编程语言,对Haskell有较大影响)。

曾经列表推导式被称为集合抽象,由于抽象(abstractions)这个词语的英文单词在若干个地方有用到,其意思太多了,所以引入了推导式(comprehensions)这样一个词语。从数学上的策梅洛-弗兰克尔集合论(Zermelo-Fraenkel Set Theory)(http://en.wikipedia.org/wiki/Zermelo-Frankel_set_theory) 来看,列表推导式和集合推导式类似。比如求集合A中奇数的平方

B = {square x | x ∈ A & odd x}

上面的这个示例,如果A集合是{1,2,3,4},那么B集合为{1,9}

如果我们把这些数学符号换成常见的编程符号,如:

ys = [square x | x <- xs; odd x]

或者我们将<-再变为for in,再加上if语句,是不是就是Python的列表推导式了。

vec = [1, 2, 3, 4]
rs = [x * x for x in vec if x % 2 != 0]
print rs

对应上面的Python示例,我们看下在Python中,列表推导式的一般形式:

[表达式 for item1 in 序列1 ... for itemN in 序列N if 条件表达式]

上面的表达式分为三部分,最左边是生成每个元素的表达式,然后是for 迭代过程,最右边可以设定一个if 判断作为过滤条件。

[]内的列表写以写为一行,也可以写为多行,一般来说多行更易读些,看个人喜好吧。

对于Python而言,列表推导式(List Comprehensions)是其最强有力的语法之一,常用于从集合对象中有选择地获取并计算元素,虽然多数情况下可以使用for、if等语句组合完成同样的任务。

其本质是一种语法糖,它提供了一种简洁高效的方式来创建列表和迭代器, 而不必借助map(), filter(), 或者lambda。
简单的列表推导可以比其它的列表创建方法更加清晰简单. 生成器表达式可以十分高效, 因为它们避免了创建整个列表。这里的优点一般是指使用简单的列表推导式时,而对于复杂的列表推导式虽然可以高效,但是生成的表达式可能难以阅读(不排除通过某些注释或排版达到优化可读性的目的)。列表推导式适用于简单情况. 每个部分应该单独置于一行: 映射表达式, for语句, 过滤器表达式. 禁止多重for语句或过滤器表达式. 复杂情况下还是使用循环吧。

如果我们要用PHP去实现列表推导式,应当如何表现呢?(这里假设我们需要实现这样一个语法糖)

有如下想法,其一般形式如下:

list{表达式1, 表达式2, ... if (条件表达式),  $list1 as $key1 => $row1, $list2 as $key2 => $row2, ...}
 
 
//如下示例:
 
list{echo $key1, echo $row2, if ($key1 > $key2), $a as $key => $row, $b as $key2 => $row2, }

在if语句前可以有多个表达式处理,以逗号隔开;
在if语句后面可以有多个列表,以逗号隔开;

也许这个YY有点纠结,只是对于PHP来说,这个糖果也许没那么重要?

参考资料:

Jones – 《The Implementation of Functional Programming Languages》, PH, 1987

http://zh-google-styleguide.googlecode.com/hg-history/2a227ce093e7b70085818bba22061d9393f3bb99/pyguide/python_language_rules.txt

关于列表推导式》上有1条评论

  1. TonySeek

    哈哈,就觉得推导式很像集合的定义。

    其实我觉得 PHP 还是挺需要这个糖的,用 array_map 和 array_filter 组合写出来的代码可读性非常不好,foreach 又要单独弄个容器去收集产生的新集合……毕竟已经是脚本语言了,像 C/Java 那样去写还是很不爽的。

    回复

TonySeek进行回复 取消回复

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


*

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>