1118-列表速构(Comprehension)
22========
3- [ 生成器和过滤器] ( #182-%E7%94%9F%E6%88%90%E5%99%A8%E5%92%8C%E8%BF%87%E6%BB%A4%E5%99%A8 ) <br />
4- [ 比特串生成器] ( #182-bitstring%E7%94%9F%E6%88%90%E5%99%A8 ) <br />
5- [ Into] ( #183-into ) <br />
63
7- > Comprehensions翻译成“速构”不知道贴不贴切,这参照了《Erlang/OTP in Action》译者的用辞。
8- “速构”是函数式语言中常见的概念,它大体上指的是用一套规则(比如从另一个列表,过滤掉一些元素)来生成元素填充新列表。
9- 这个概念我们在中学的数学课上就可能已经接触过,在大学高数中更为常见:如``` { x | x ∈ N } ``` ,指的是这个集合里所有元素是自然数。
10- 该集合是由自然数集合的元素映射生成过来的。相关知识可见[ WIKI] ( http://en.wikipedia.org/wiki/List_comprehension ) 。
4+ > * Comprehensions* 翻译成“速构”不知道贴不贴切,
5+ 这参照了《Erlang/OTP in Action》译者的用辞。国内一些Python书(是的,Python也有这个概念)
6+ 中翻译为“推导式”、“递推式”。不过这里请不要纠结它翻译成啥,主要是弄明白它是啥。本章
7+ (或者本文)中出现的话,一般翻译成“速构”或是保留英文。
8+ “速构”是函数式语言中常见的概念,它大体上指的是用一套规则(比如从另一个列表,过滤掉一些元素)
9+ 来生成元素填充新列表。
10+ 这个概念我们在中学的数学课上其实就已经接触过,在大学高数中更为常见:
11+ 如``` { x | x ∈ N } ``` ,字面上意思是其表示了一个集合,这个集合里所有元素属于自然数N范围
12+ (也就是自然数集合)。
13+ 相关知识可见[ WIKI] ( http://en.wikipedia.org/wiki/List_comprehension ) 。
1114
12- Elixir中,使用枚举类型(如列表)来做循环操作是很常见的。对对象列表进行枚举时,通常要有选择性地过滤掉其中一些元素,还有可能做一些变换。列表速构(comprehensions)就是为此目的诞生的语法糖:把这些常见任务分组,放到特殊的``` for ``` 中执行。
15+ Elixir中,使用枚举类型(如列表)来做循环操作是很常见的。对对象列表进行枚举时,
16+ 通常要有选择性地过滤掉其中一些元素,还有可能做一些变换。
17+ 列表速构(comprehensions)就是为此目的诞生的语法糖:把这些常见任务分组,
18+ 放到特殊的``` for ``` 中执行。
1319
1420例如,我们可以这样计算列表中每个元素的平方:
15- ```
21+ ``` elixir
1622iex> for n <- [1 , 2 , 3 , 4 ], do: n * n
1723[1 , 4 , 9 , 16 ]
1824```
@@ -26,33 +32,35 @@ S = { X^2 | X ∈ [1,4], X ∈ N}
2632一个列表速构由三部分组成:生成器,过滤器和收集器。
2733
2834##18 .2-生成器和过滤器
29- 在上面的例子中,``` n <- [1, 2, 3, 4] ``` 就是生成器。它字面意思上生成了即将要在速构中使用的数值。
30- 任何枚举类型都可以传递给生成器表达式的右端:
31- ```
35+ 在上面的例子中,``` n <- [1, 2, 3, 4] ``` 就是生成器。
36+ 它字面意思上生成了即将要在速构中使用的数值。 任何枚举类型都可以传递给生成器表达式的右端:
37+ ``` elixir
3238iex> for n <- 1 .. 4 , do: n * n
3339[1 , 4 , 9 , 16 ]
3440```
3541这个例子中的生成器是一个__ 范围__ 。
3642
3743生成器表达式支持模式匹配,它会忽略所有不匹配的模式。
38- 想象一下如果不用范围而是用一个键值列表,键只有``` :good ``` 和``` :bad ``` 两种,来计算中间被标记成‘good’的元素的平方:
39- ```
44+ 想象一下如果不用范围而是用一个键值列表,键只有``` :good ``` 和``` :bad ``` 两种,
45+ 来计算中间被标记成‘good’的元素的平方:
46+ ``` elixir
4047iex> values = [good: 1 , good: 2 , bad: 3 , good: 4 ]
4148iex> for {:good , n} <- values, do: n * n
4249[1 , 4 , 16 ]
4350```
4451
4552过滤器能过滤掉某些产生的值。例如我们可以只对奇数进行平方运算:
46- ```
53+ ``` elixir
4754iex> require Integer
4855iex> for n <- 1 .. 4 , Integer .odd? (n), do: n * n
4956[1 , 9 ]
5057```
5158过滤器会保留所有判断结果是非nil或非false的值。
5259
5360总的来说,速构比直接使用枚举或流模块的函数提供了更精确的表述。
54- 不但如此,速构还接受多个生成器和过滤器。下面就是一个例子,代码接受目录列表,删除这些目录下的所有文件:
55- ```
61+ 不但如此,速构还接受多个生成器和过滤器。下面就是一个例子,代码接受目录列表,
62+ 删除这些目录下的所有文件:
63+ ``` elixir
5664for dir <- dirs,
5765 file <- File .ls! (dir),
5866 path = Path .join (dir, file),
@@ -61,12 +69,14 @@ for dir <- dirs,
6169end
6270```
6371
64- 需要记住的是,在速构中,变量赋值这种事应在生成器中进行。因为在过滤器或代码块中的赋值操作不会反映到速构外面去。
72+ 需要记住的是,在速构中,变量赋值这种事应在生成器中进行。
73+ 因为在过滤器或代码块中的赋值操作不会反映到速构外面去。
6574
6675## 18.2-比特串生成器
6776速构也支持比特串作为生成器,而且这种生成器在组织处理比特串的流时非常有用。
68- 下面的例子中,程序从二进制数据(表示为<<像素1的R值,像素1的G值,像素1的B值,像素2的R值,像素2的G...>>)中接收一个像素的列表,把它们转换为元组:
69- ```
77+ 下面的例子中,程序从二进制数据(表示为<<像素1的R值,像素1的G值,像素1的B值,
78+ 像素2的R值,像素2的G...>>)中接收一个像素的列表,把它们转换为元组:
79+ ``` elixir
7080iex> pixels = << 213 , 45 , 132 , 64 , 76 , 32 , 76 , 0 , 0 , 234 , 32 , 15 >>
7181iex> for << r:: 8 , g:: 8 , b:: 8 <- pixels>> , do: {r, g, b}
7282[{213 ,45 ,132 },{64 ,76 ,32 },{76 ,0 ,0 },{234 ,32 ,15 }]
@@ -77,7 +87,7 @@ iex> for <<r::8, g::8, b::8 <- pixels>>, do: {r, g, b}
7787在上面的例子中,速构返回一个列表作为结果。
7888但是,通过使用``` :into ``` 选项,速构的结果可以插入到一个不同的数据结构中。
7989例如,你可以使用比特串生成器加上``` :into ``` 来轻松地构成无空格字符串:
80- ```
90+ ``` elixir
8191iex> for << c <- " hello world " >> , c != ?\s , into: " " , do: << c>>
8292" helloworld"
8393```
@@ -86,7 +96,7 @@ iex> for <<c <- " hello world ">>, c != ?\s, into: "", do: <<c>>
8696
8797例如,IO模块提供了流。流既是Enumerable也是Collectable。
8898你可以使用速构实现一个回声终端,让其返回任何输入的东西的大写形式:
89- ```
99+ ``` elixir
90100iex> stream = IO .stream (:stdio , :line )
91101iex> for line <- stream, into: stream do
92102.. .> String .upcase (line) <> " \n "
@@ -95,4 +105,3 @@ iex> for line <- stream, into: stream do
95105
96106现在在终端中输入任意字符串,你会看到同样的内容以大写形式被打印出来。
97107不幸的是,这个例子会让你的shell陷入到该速构代码中,只能用Ctrl+C两次来退出。
98-
0 commit comments