elixir官方入门教程 推导式
2016-08-05 00:00
218 查看
摘要: elixir
#推导式
发生器和筛选器
位串生成器
在Elixir中,经常需要遍历一个枚举体,过滤掉一些结果,然后将值映射到另一个列表.推导式就是这种结构的语法糖:它将这些普遍的任务集合到
例如,我们可以将一个整数列表映射到它们的平方:
一个推导式由三个部分组成:发生器,筛选器和收集器.
#发生器和筛选器
在上述表达式中,
生成器表达式的左边也支持模式匹配;所有不能匹配的都会被忽略.想象一下,表达式右边不再是一个范围,而是一个有着原子键
除了模式匹配之外,筛选器可以用于选择一些特定的元素.例如,我们可以选出3的倍数:
推导式将所有筛选器表达式结果为
推导式通常提供比使用
多重发生器也可以用于计算两个列表的笛卡尔乘积:
一个更好的关于多重发生器和筛选器的案例是勾股数.勾股数是指满足
然后在终端中运行:
当搜索范围是一个巨大的数时,上述代码会非常昂贵.此外,由于
最后,记住推导式内部的变量赋值,即发生器,筛选器或块内的,不会影响到推导式的外部.
#位串发生器
当你想要推导位串流的时候,位串发生器就非常有用了.下面的例子从一个二进制数中接收了一个由像素组成的列表,其中有他们的rgb值,然后将它们转换成了三元素元组:
位串发生器可以与"正宗"枚举发生器相混合,并且支持筛选器.
#
在上述例子中,所有推导式都以列表作为返回值.然而,推导式的结果可以被插入不同的数据结构,通过传送
例如,位串发生器可以和
集合,映射等其它的词典结构也可以被传递给
一个普遍的
让我们看一个使用流的例子.因为
现在输入任意字符到终端中,你会看到相应的大写值打印出来.不幸的是,这个例子会使你的IEx壳陷入推导式中,所以你需要敲击两次
#推导式
发生器和筛选器
位串生成器
:into设置
在Elixir中,经常需要遍历一个枚举体,过滤掉一些结果,然后将值映射到另一个列表.推导式就是这种结构的语法糖:它将这些普遍的任务集合到
for格式中.
例如,我们可以将一个整数列表映射到它们的平方:
iex> for n <- [1, 2, 3, 4], do: n * n [1, 4, 9, 16]
一个推导式由三个部分组成:发生器,筛选器和收集器.
#发生器和筛选器
在上述表达式中,
n <- [1, 2, 3, 4]是发生器.它会生成在推导式中使用的值.任何枚举体都可以被传送到发生器表达式的右边:
iex> for n <- 1..4, do: n * n [1, 4, 9, 16]
生成器表达式的左边也支持模式匹配;所有不能匹配的都会被忽略.想象一下,表达式右边不再是一个范围,而是一个有着原子键
:good和
:bad的关键词列表,而我们只想要计算
:good值的平方:
iex> values = [good: 1, good: 2, bad: 3, good: 4] iex> for {:good, n} <- values, do: n * n [1, 4, 16]
除了模式匹配之外,筛选器可以用于选择一些特定的元素.例如,我们可以选出3的倍数:
iex> multiple_of_3? = fn(n) -> rem(n, 3) == 0 end iex> for n <- 0..5, multiple_of_3?.(n), do: n * n [0, 9]
推导式将所有筛选器表达式结果为
false或
nil的元素过滤掉了;其它所有值都被选入.
推导式通常提供比使用
Enum和
Stream模块中的相等函数更加简洁的表达方法.而且,推导式也允许指定多重生成器和筛选器.这里有一个例子,接收一个目录组成的列表,然后得到这些目录中每个文件的大小:
for dir <- dirs, file <- File.ls!(dir), path = Path.join(dir, file), File.regular?(path) do File.stat!(path).size end
多重发生器也可以用于计算两个列表的笛卡尔乘积:
iex> for i <- [:a, :b, :c], j <- [1, 2], do: {i, j} [a: 1, a: 2, b: 1, b: 2, c: 1, c: 2]
一个更好的关于多重发生器和筛选器的案例是勾股数.勾股数是指满足
a*a + b*b = c*c的正整数,让我们在文件
triple.exs中编写一个推导式:
defmodule Triple do def pythagorean(n) when n > 0 do for a <- 1..n, b <- 1..n, c <- 1..n, a + b + c <= n, a*a + b*b == c*c, do: {a, b, c} end end
然后在终端中运行:
iex triple.exs
iex> Triple.pythagorean(5) [] iex> Triple.pythagorean(12) [{3, 4, 5}, {4, 3, 5}] iex> Triple.pythagorean(48) [{3, 4, 5}, {4, 3, 5}, {5, 12, 13}, {6, 8, 10}, {8, 6, 10}, {8, 15, 17}, {9, 12, 15}, {12, 5, 13}, {12, 9, 15}, {12, 16, 20}, {15, 8, 17}, {16, 12, 20}]
当搜索范围是一个巨大的数时,上述代码会非常昂贵.此外,由于
{b, a, c}和
{a, b, c}是相同的勾股数,所以我们的函数生成重复结果.我们可以优化推导式来消除重复的结果,即在后面引用先前发生器中的变量,例如:
defmodule Triple do def pythagorean(n) when n > 0 do for a <- 1..n-2, b <- a+1..n-1, c <- b+1..n, a + b + c <= n, a*a + b*b == c*c, do: {a, b, c} end end
最后,记住推导式内部的变量赋值,即发生器,筛选器或块内的,不会影响到推导式的外部.
#位串发生器
当你想要推导位串流的时候,位串发生器就非常有用了.下面的例子从一个二进制数中接收了一个由像素组成的列表,其中有他们的rgb值,然后将它们转换成了三元素元组:
iex> pixels = <<213, 45, 132, 64, 76, 32, 76, 0, 0, 234, 32, 15>> iex> for <<r::8, g::8, b::8 <- pixels>>, do: {r, g, b} [{213, 45, 132}, {64, 76, 32}, {76, 0, 0}, {234, 32, 15}]
位串发生器可以与"正宗"枚举发生器相混合,并且支持筛选器.
#
:into选项
在上述例子中,所有推导式都以列表作为返回值.然而,推导式的结果可以被插入不同的数据结构,通过传送
:into选项给推导式.
例如,位串发生器可以和
:into选项配合使用,来简单地消除字符串中的空格:
iex> for <<c <- " hello world ">>, c != ?\s, into: "", do: <<c>> "helloworld"
集合,映射等其它的词典结构也可以被传递给
:into选项.通常,
:into接受可以实现
Collectable协议的任何结构.
一个普遍的
:into使用场景是不接触键,就能改变映射中的值:
iex> for {key, val} <- %{"a" => 1, "b" => 2}, into: %{}, do: {key, val * val} %{"a" => 1, "b" => 4}
让我们看一个使用流的例子.因为
IO模块提供了流(满足
Enumerable和
Collectable),我们可以用推导式来实现一个返回输入内容的大写版本的回声终端:
iex> stream = IO.stream(:stdio, :line) iex> for line <- stream, into: stream do ...> String.upcase(line) <> "\n" ...> end
现在输入任意字符到终端中,你会看到相应的大写值打印出来.不幸的是,这个例子会使你的IEx壳陷入推导式中,所以你需要敲击两次
Ctrl+C来退出它.:)
相关文章推荐
- elixir官方入门教程 基本操作符
- elixir官方入门教程 关键词和映射
- elixir官方教程Mix与OTP(一) Mix入门
- elixir官方入门教程 基本类型
- elixir官方入门教程 学习资料
- elixir官方入门教程 类型规格与行为
- elixir官方入门教程 递归
- elixir官方入门教程 别名,要求与进口
- elixir官方入门教程 进程
- elixir官方入门教程 case,cond和if
- elixir官方入门教程 模块
- elixir官方入门教程 结构体
- elixir官方入门教程 模块属性
- elixir官方入门教程 印记
- elixir官方入门教程 Erlang库
- elixir官方入门教程 协议
- elixir官方入门教程 尝试,抓取和解救
- elixir官方入门教程 IO与文件系统
- elixir官方入门教程 枚举接口与流
- elixir官方入门教程 模式匹配